From d876d20d66618663d4a3620df93423967a003604 Mon Sep 17 00:00:00 2001 From: Roger Liao Date: Wed, 13 May 2026 22:33:36 +0000 Subject: [PATCH 1/2] Revert to original patch in c10cae9a6344ff Signed-off-by: Roger Liao --- patches-sonic/aspeed-ast2700-support.patch | 103342 ++++++++---------- 1 file changed, 48102 insertions(+), 55240 deletions(-) diff --git a/patches-sonic/aspeed-ast2700-support.patch b/patches-sonic/aspeed-ast2700-support.patch index edc5a1c55..cc9a6c492 100644 --- a/patches-sonic/aspeed-ast2700-support.patch +++ b/patches-sonic/aspeed-ast2700-support.patch @@ -1,5 +1,5 @@ From: Chander -Date: Wed, 08 Apr 2026 18:03:52 +0000 +Date: Tue, 23 Dec 2025 10:16:25 +0000 Subject: [PATCH] Add Aspeed AST2700 support This patch adds support for Aspeed AST2700 ARM64 SoC including: @@ -12,14 +12,13 @@ Signed-off-by: Chander --- 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 2026-04-08 18:03:48.534701227 +0000 -@@ -40,6 +40,13 @@ ++++ 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" -+ select AST2700_IRQ + help + Say yes if you intend to run on an Aspeed ast2700 or similar + seventh generation Aspeed BMCs. @@ -28,8 +27,8 @@ diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms 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-04-08 18:03:23.250162666 +0000 -+++ b/arch/arm64/boot/dts/Makefile 2026-04-08 18:03:48.565700661 +0000 +--- 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 @@ -40,8 +39,8 @@ diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile 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 2026-04-08 18:03:31.587010606 +0000 -@@ -0,0 +1,27 @@ ++++ b/arch/arm64/boot/dts/aspeed/Makefile 2025-12-23 10:16:06.861271783 +0000 +@@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0 + +dtb-$(CONFIG_ARCH_ASPEED) += \ @@ -57,21 +56,10 @@ 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 \ -+ 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 ++ ast2700-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 2026-04-08 18:03:31.587010606 +0000 ++++ b/arch/arm64/boot/dts/aspeed/aspeed-evb-flash-layout-128.dtsi 2025-12-23 10:16:06.861271783 +0000 @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0+ + @@ -107,7 +95,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 2026-04-08 18:03:31.587010606 +0000 ++++ b/arch/arm64/boot/dts/aspeed/aspeed-evb-flash-layout-256-abr.dtsi 2025-12-23 10:16:06.861271783 +0000 @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0+ + @@ -168,7 +156,7 @@ 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 2026-04-08 18:03:31.587010606 +0000 ++++ b/arch/arm64/boot/dts/aspeed/aspeed-g7-pinctrl.dtsi 2025-12-23 10:16:06.861271783 +0000 @@ -0,0 +1,1425 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2025 ASPEED Corp. @@ -1597,8 +1585,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 2026-04-08 18:03:31.587010606 +0000 -@@ -0,0 +1,2923 @@ ++++ b/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi 2025-12-23 10:16:06.862271766 +0000 +@@ -0,0 +1,2870 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include @@ -1850,7 +1838,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + pinctrl-0 = <&pinctrl_usb2axhpd1_default>; + aspeed,device = <&pcie_cfg0>; + aspeed,scu = <&syscon0>; -+ aspeed,enlarge-fifo; + status = "disabled"; + }; + @@ -1884,7 +1871,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + pinctrl-0 = <&pinctrl_usb2bxhpd1_default>; + aspeed,device = <&pcie_cfg1>; + aspeed,scu = <&syscon0>; -+ aspeed,enlarge-fifo; + status = "disabled"; + }; + @@ -2143,7 +2129,8 @@ 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 = <0x02000000 0x0 0x60000000 0x0 0x60000000 0x0 0x20000000>; ++ ranges = <0x01000000 0x0 0x00000000 0x0 0x00000000 0x0 0x00008000>, /* I/O */ ++ <0x02000000 0x0 0x60000000 0x0 0x60000000 0x0 0x20000000>; /* memory */ + interrupts = ; + resets = <&syscon0 SCU0_RESET_H2X0>, + <&syscon0 SCU0_RESET_PCIE0RST>; @@ -2180,7 +2167,8 @@ 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 = <0x02000000 0 0x80000000 0x0 0x80000000 0x0 0x20000000>; ++ ranges = <0x01000000 0 0x00000000 0x0 0x00000000 0x0 0x00008000>, ++ <0x02000000 0 0x80000000 0x0 0x80000000 0x0 0x20000000>; /* memory */ + interrupts = ; + resets = <&syscon0 SCU0_RESET_H2X1>, + <&syscon0 SCU0_RESET_PCIE1RST>; @@ -2297,18 +2285,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; + }; + @@ -2390,7 +2378,6 @@ 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>, @@ -2437,8 +2424,6 @@ 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; @@ -2448,8 +2433,6 @@ 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; @@ -2459,8 +2442,6 @@ 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; @@ -2470,8 +2451,6 @@ 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; @@ -2905,6 +2884,18 @@ 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>; @@ -2913,8 +2904,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + clocks = <&syscon1 SCU1_CLK_GATE_MAC0CLK>; + resets = <&syscon1 SCU1_RESET_MAC0>; + status = "disabled"; -+ -+ aspeed,scu = <&syscon1>; + }; + + mac1: ethernet@14060000 { @@ -2925,8 +2914,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + clocks = <&syscon1 SCU1_CLK_GATE_MAC1CLK>; + resets = <&syscon1 SCU1_RESET_MAC1>; + status = "disabled"; -+ -+ aspeed,scu = <&syscon1>; + }; + + mac2: ethernet@14070000 { @@ -2940,8 +2927,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7.dtsi b/arch/arm64/boot/dts/asp + clocks = <&syscon1 SCU1_CLK_GATE_MAC2CLK>; + resets = <&syscon1 SCU1_RESET_MAC2>; + status = "disabled"; -+ -+ aspeed,scu = <&syscon1>; + }; + + sdio_controller: sdc@14080000 { @@ -2983,7 +2968,8 @@ 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 = <0x02000000 0 0xa0000000 0x0 0xa0000000 0x0 0x20000000>; ++ ranges = <0x01000000 0 0x00000000 0x0 0x00000000 0x0 0x00008000>, ++ <0x02000000 0 0xa0000000 0x0 0xa0000000 0x0 0x20000000>; /* memory */ + interrupts-extended = <&intc1_4 31>; + resets = <&syscon1 SCU1_RESET_H2X>, + <&syscon1 SCU1_RESET_PCIE2RST>; @@ -3106,19 +3092,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>; -+ -+ 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>; @@ -3128,24 +3101,19 @@ 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; + }; + @@ -3399,7 +3367,6 @@ 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 { @@ -3704,48 +3671,36 @@ 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"; + }; + @@ -3916,7 +3871,6 @@ 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"; + }; + @@ -3931,7 +3885,6 @@ 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"; + }; + @@ -3946,7 +3899,6 @@ 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"; + }; + @@ -3961,7 +3913,6 @@ 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"; + }; + @@ -3976,7 +3927,6 @@ 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"; + }; + @@ -3991,7 +3941,6 @@ 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"; + }; + @@ -4006,7 +3955,6 @@ 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"; + }; + @@ -4021,7 +3969,6 @@ 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"; + }; + @@ -4035,7 +3982,6 @@ 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"; + }; + @@ -4049,7 +3995,6 @@ 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"; + }; + @@ -4063,7 +4008,6 @@ 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"; + }; + @@ -4076,7 +4020,6 @@ 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"; + }; + @@ -4106,14 +4049,10 @@ 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>, -+ <0x0 0x14c34200 0x0 0x100>, -+ <0x0 0x14c34800 0x0 0x100>; -+ reg-names = "base", "phy", "top"; ++ reg = <0x0 0x14c34000 0x0 0x100>; + 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"; @@ -4133,14 +4072,10 @@ 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>, -+ <0x0 0x14c35200 0x0 0x100>, -+ <0x0 0x14c35800 0x0 0x100>; -+ reg-names = "base", "phy", "top"; ++ reg = <0x0 0x14c35000 0x0 0x100>; + 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"; @@ -4220,7 +4155,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_fsi2_default>; ++ pinctrl-0 = <&pinctrl_fsi1_default>; + clocks = <&syscon1 SCU1_CLK_GATE_FSICLK>; + resets = <&syscon1 SCU1_RESET_FSI>; + status = "disabled"; @@ -4254,7 +4189,7 @@ 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 0xA0>, <0x1C0 0x40>; ++ reg = <0x100 0x80>, <0x1A0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; + aspeed,enable-dma; @@ -4271,7 +4206,7 @@ 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 0xA0>, <0x2C0 0x40>; ++ reg = <0x200 0x80>, <0x2A0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; + aspeed,enable-dma; @@ -4288,7 +4223,7 @@ 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 0xA0>, <0x3C0 0x40>; ++ reg = <0x300 0x80>, <0x3A0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; + aspeed,enable-dma; @@ -4305,7 +4240,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 0xA0>, <0x4C0 0x40>; ++ reg = <0x400 0x80>, <0x4A0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; + clocks = <&syscon1 SCU1_CLK_APB>; @@ -4321,7 +4256,7 @@ 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 0xA0>, <0x5C0 0x40>; ++ reg = <0x500 0x80>, <0x5A0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; + aspeed,enable-dma; @@ -4338,7 +4273,7 @@ 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 0xA0>, <0x6C0 0x40>; ++ reg = <0x600 0x80>, <0x6A0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; + aspeed,enable-dma; @@ -4355,7 +4290,7 @@ 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 0xA0>, <0x7C0 0x40>; ++ reg = <0x700 0x80>, <0x7A0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; + aspeed,enable-dma; @@ -4372,7 +4307,7 @@ 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 0xA0>, <0x8C0 0x40>; ++ reg = <0x800 0x80>, <0x8A0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; + aspeed,enable-dma; @@ -4389,7 +4324,7 @@ 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 0xA0>, <0x9C0 0x40>; ++ reg = <0x900 0x80>, <0x9A0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; + aspeed,enable-dma; @@ -4406,7 +4341,7 @@ 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 0xA0>, <0xAC0 0x40>; ++ reg = <0xA00 0x80>, <0xAA0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; + aspeed,enable-dma; @@ -4423,7 +4358,7 @@ 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 0xA0>, <0xBC0 0x40>; ++ reg = <0xB00 0x80>, <0xBA0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; + aspeed,enable-dma; @@ -4440,7 +4375,7 @@ 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 0xA0>, <0xCC0 0x40>; ++ reg = <0xC00 0x80>, <0xCA0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; + aspeed,enable-dma; @@ -4457,7 +4392,7 @@ 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 0xA0>, <0xDC0 0x40>; ++ reg = <0xD00 0x80>, <0xDA0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; + aspeed,enable-dma; @@ -4474,7 +4409,7 @@ 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 0xA0>, <0xEC0 0x40>; ++ reg = <0xE00 0x80>, <0xEA0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; + aspeed,enable-dma; @@ -4491,7 +4426,7 @@ 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 0xA0>, <0xFC0 0x40>; ++ reg = <0xF00 0x80>, <0xFA0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; + aspeed,enable-dma; @@ -4508,7 +4443,7 @@ 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 0xA0>, <0x10C0 0x40>; ++ reg = <0x1000 0x80>, <0x10A0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <&i2c_global>; + aspeed,enable-dma; @@ -4524,7 +4459,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 2026-04-08 18:03:31.587010606 +0000 ++++ b/arch/arm64/boot/dts/aspeed/aspeed-ltpi0-pinctrl.dtsi 2025-12-23 10:16:06.862271766 +0000 @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + @@ -4937,7 +4872,7 @@ 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 2026-04-08 18:03:31.587010606 +0000 ++++ b/arch/arm64/boot/dts/aspeed/aspeed-ltpi0.dtsi 2025-12-23 10:16:06.862271766 +0000 @@ -0,0 +1,659 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include @@ -5329,7 +5264,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 0xA0>, <0x1C0 0x40>; ++ reg = <0x100 0x80>, <0x1a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5346,7 +5281,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 0xA0>, <0x2C0 0x40>; ++ reg = <0x200 0x80>, <0x2a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5363,7 +5298,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 0xA0>, <0x3C0 0x40>; ++ reg = <0x300 0x80>, <0x3a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5380,7 +5315,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 0xA0>, <0x4C0 0x40>; ++ reg = <0x400 0x80>, <0x4a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5397,7 +5332,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 0xA0>, <0x5C0 0x40>; ++ reg = <0x500 0x80>, <0x5a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5414,7 +5349,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 0xA0>, <0x6C0 0x40>; ++ reg = <0x600 0x80>, <0x6a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5431,7 +5366,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 0xA0>, <0x7C0 0x40>; ++ reg = <0x700 0x80>, <0x7a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5448,7 +5383,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 0xA0>, <0x8C0 0x40>; ++ reg = <0x800 0x80>, <0x8a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5465,7 +5400,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 0xA0>, <0x9C0 0x40>; ++ reg = <0x900 0x80>, <0x9a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5482,7 +5417,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 0xA0>, <0xAC0 0x40>; ++ reg = <0xa00 0x80>, <0xaa0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5499,7 +5434,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 0xA0>, <0xBC0 0x40>; ++ reg = <0xb00 0x80>, <0xba0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5516,7 +5451,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 0xA0>, <0xCC0 0x40>; ++ reg = <0xc00 0x80>, <0xca0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5533,7 +5468,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 0xA0>, <0xDC0 0x40>; ++ reg = <0xd00 0x80>, <0xda0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5550,7 +5485,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 0xA0>, <0xEC0 0x40>; ++ reg = <0xe00 0x80>, <0xea0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5567,7 +5502,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 0xA0>, <0xFC0 0x40>; ++ reg = <0xf00 0x80>, <0xfa0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5584,7 +5519,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 0xA0>, <0x10C0 0x40>; ++ reg = <0x1000 0x80>, <0x10a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -5600,7 +5535,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 2026-04-08 18:03:31.587010606 +0000 ++++ b/arch/arm64/boot/dts/aspeed/aspeed-ltpi1-pinctrl.dtsi 2025-12-23 10:16:06.862271766 +0000 @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + @@ -6013,7 +5948,7 @@ 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 2026-04-08 18:03:31.587010606 +0000 ++++ b/arch/arm64/boot/dts/aspeed/aspeed-ltpi1.dtsi 2025-12-23 10:16:06.862271766 +0000 @@ -0,0 +1,659 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include @@ -6405,7 +6340,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 0xA0>, <0x1C0 0x40>; ++ reg = <0x100 0x80>, <0x1a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6422,7 +6357,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 0xA0>, <0x2C0 0x40>; ++ reg = <0x200 0x80>, <0x2a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6439,7 +6374,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 0xA0>, <0x3C0 0x40>; ++ reg = <0x300 0x80>, <0x3a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6456,7 +6391,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 0xA0>, <0x4C0 0x40>; ++ reg = <0x400 0x80>, <0x4a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6473,7 +6408,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 0xA0>, <0x5C0 0x40>; ++ reg = <0x500 0x80>, <0x5a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6490,7 +6425,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 0xA0>, <0x6C0 0x40>; ++ reg = <0x600 0x80>, <0x6a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6507,7 +6442,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 0xA0>, <0x7C0 0x40>; ++ reg = <0x700 0x80>, <0x7a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6524,7 +6459,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 0xA0>, <0x8C0 0x40>; ++ reg = <0x800 0x80>, <0x8a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6541,7 +6476,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 0xA0>, <0x9C0 0x40>; ++ reg = <0x900 0x80>, <0x9a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6558,7 +6493,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 0xA0>, <0xAC0 0x40>; ++ reg = <0xa00 0x80>, <0xaa0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6575,7 +6510,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 0xA0>, <0xBC0 0x40>; ++ reg = <0xb00 0x80>, <0xba0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6592,7 +6527,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 0xA0>, <0xCC0 0x40>; ++ reg = <0xc00 0x80>, <0xca0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6609,7 +6544,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 0xA0>, <0xDC0 0x40>; ++ reg = <0xd00 0x80>, <0xda0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6626,7 +6561,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 0xA0>, <0xEC0 0x40>; ++ reg = <0xe00 0x80>, <0xea0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6643,7 +6578,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 0xA0>, <0xFC0 0x40>; ++ reg = <0xf00 0x80>, <0xfa0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6660,7 +6595,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 0xA0>, <0x10C0 0x40>; ++ reg = <0x1000 0x80>, <0x10a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi1_i2c_global>; + aspeed,enable-dma; @@ -6676,7 +6611,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 2026-04-08 18:03:31.587010606 +0000 ++++ b/arch/arm64/boot/dts/aspeed/aspeed-ltpi1800.dtsi 2025-12-23 10:16:06.862271766 +0000 @@ -0,0 +1,647 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include @@ -7056,7 +6991,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 0xA0>, <0x1C0 0x40>; ++ reg = <0x100 0x80>, <0x1a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7073,7 +7008,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 0xA0>, <0x2C0 0x40>; ++ reg = <0x200 0x80>, <0x2a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7090,7 +7025,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 0xA0>, <0x3C0 0x40>; ++ reg = <0x300 0x80>, <0x3a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7107,7 +7042,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 0xA0>, <0x4C0 0x40>; ++ reg = <0x400 0x80>, <0x4a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7124,7 +7059,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 0xA0>, <0x5C0 0x40>; ++ reg = <0x500 0x80>, <0x5a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7141,7 +7076,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 0xA0>, <0x6C0 0x40>; ++ reg = <0x600 0x80>, <0x6a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7158,7 +7093,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 0xA0>, <0x7C0 0x40>; ++ reg = <0x700 0x80>, <0x7a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7175,7 +7110,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 0xA0>, <0x8C0 0x40>; ++ reg = <0x800 0x80>, <0x8a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7192,7 +7127,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 0xA0>, <0x9C0 0x40>; ++ reg = <0x900 0x80>, <0x9a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7209,7 +7144,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 0xA0>, <0xAC0 0x40>; ++ reg = <0xa00 0x80>, <0xaa0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7226,7 +7161,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 0xA0>, <0xBC0 0x40>; ++ reg = <0xb00 0x80>, <0xba0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7243,7 +7178,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 0xA0>, <0xCC0 0x40>; ++ reg = <0xc00 0x80>, <0xca0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7260,7 +7195,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 0xA0>, <0xDC0 0x40>; ++ reg = <0xd00 0x80>, <0xda0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7277,7 +7212,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 0xA0>, <0xEC0 0x40>; ++ reg = <0xe00 0x80>, <0xea0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7294,7 +7229,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 0xA0>, <0xFC0 0x40>; ++ reg = <0xf00 0x80>, <0xfa0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7311,7 +7246,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 0xA0>, <0x10C0 0x40>; ++ reg = <0x1000 0x80>, <0x10a0 0x20>; + compatible = "aspeed,ast2700-i2c"; + aspeed,global-regs = <<pi0_i2c_global>; + aspeed,enable-dma; @@ -7327,8 +7262,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 2026-04-08 18:03:31.587010606 +0000 -@@ -0,0 +1,127 @@ ++++ b/arch/arm64/boot/dts/aspeed/ast2700-ci-host.dts 2025-12-23 10:16:06.862271766 +0000 +@@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/dts-v1/; @@ -7426,40 +7361,10 @@ 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>; -+}; 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 2026-04-08 18:03:31.587010606 +0000 -@@ -0,0 +1,973 @@ ++++ b/arch/arm64/boot/dts/aspeed/ast2700-dcscm.dts 2025-12-23 10:16:06.862271766 +0000 +@@ -0,0 +1,978 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/dts-v1/; @@ -7955,6 +7860,13 @@ 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"; +}; @@ -8044,7 +7956,6 @@ 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; +}; @@ -8060,7 +7971,6 @@ 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; +}; @@ -8435,7 +8345,7 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-dcscm.dts b/arch/arm64/boot/dts/ +}; 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 2026-04-08 18:03:31.587010606 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700-dcscm_ast1700-evb-dual.dts 2025-12-23 10:16:06.862271766 +0000 @@ -0,0 +1,218 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + @@ -8657,7 +8567,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 2026-04-08 18:03:31.587010606 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700-dcscm_ast1700-evb.dts 2025-12-23 10:16:06.862271766 +0000 @@ -0,0 +1,456 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + @@ -9117,7 +9027,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 2026-04-08 18:03:31.587010606 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700-dcscm_ast1800-evb.dts 2025-12-23 10:16:06.862271766 +0000 @@ -0,0 +1,436 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + @@ -9557,7 +9467,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 2026-04-08 18:03:31.587010606 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700-evb-256-abr.dts 2025-12-23 10:16:06.862271766 +0000 @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + @@ -9601,7 +9511,7 @@ 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 2026-04-08 18:03:31.587010606 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700-evb-s0.dts 2025-12-23 10:16:06.862271766 +0000 @@ -0,0 +1,367 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + @@ -9972,8 +9882,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 2026-04-08 18:03:31.588010588 +0000 -@@ -0,0 +1,481 @@ ++++ b/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts 2025-12-23 10:16:06.862271766 +0000 +@@ -0,0 +1,465 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "ast2700-evb.dts" @@ -10409,6 +10319,10 @@ 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 { @@ -10435,30 +10349,10 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb-s1.dts b/arch/arm64/boot/dts +&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 --- 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 2026-04-08 18:03:31.588010588 +0000 -@@ -0,0 +1,1271 @@ ++++ b/arch/arm64/boot/dts/aspeed/ast2700-evb.dts 2025-12-23 10:16:06.862271766 +0000 +@@ -0,0 +1,1270 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/dts-v1/; @@ -10470,6 +10364,7 @@ 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"; @@ -10729,8 +10624,7 @@ 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_adc13_bias>; ++ &pinctrl_adc14_default &pinctrl_adc15_default>; +}; + +&pinctrl0 { @@ -10816,10 +10710,6 @@ 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 { @@ -11147,9 +11037,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/as + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rgmii0_default &pinctrl_rgmii0_driving>; -+ -+ rx-internal-delay-ps = <0>; -+ tx-internal-delay-ps = <0>; +}; + +&mac1 { @@ -11160,9 +11047,6 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/as + + 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 @@ -11196,6 +11080,13 @@ 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; @@ -11208,7 +11099,6 @@ 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 @@ -11246,7 +11136,6 @@ 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 @@ -11637,6 +11526,7 @@ 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 @@ -11671,14 +11561,16 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/as + pinctrl-0 = <&pinctrl_usb3axhp_default &pinctrl_usb2axhp_default>; +}; + -+&vhubb0 { ++&usb3bhp { + status = "okay"; -+ pinctrl-0 = <&pinctrl_usb2bhpd0_default>; +}; + -+&usb3bhp { ++&uphy2b { ++ status = "okay"; ++}; ++ ++&vhubb1 { + status = "okay"; -+ pinctrl-0 = <&pinctrl_usb3bxhp_default &pinctrl_usb2bxhp_default>; +}; + +&vhubc { @@ -11695,6 +11587,7 @@ 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 { @@ -11732,8 +11625,8 @@ 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 2026-04-08 18:03:31.588010588 +0000 -@@ -0,0 +1,1175 @@ ++++ b/arch/arm64/boot/dts/aspeed/ast2700-evbeeprom.dts 2025-12-23 10:16:06.862271766 +0000 +@@ -0,0 +1,1179 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/dts-v1/; @@ -12417,6 +12310,10 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evbeeprom.dts b/arch/arm64/boot/ + 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 { @@ -12911,8 +12808,8 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evbeeprom.dts b/arch/arm64/boot/ +}; 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 2026-04-08 18:03:31.588010588 +0000 -@@ -0,0 +1,1175 @@ ++++ b/arch/arm64/boot/dts/aspeed/ast2700-evbi2c.dts 2025-12-23 10:16:06.862271766 +0000 +@@ -0,0 +1,1179 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/dts-v1/; @@ -13596,6 +13493,10 @@ 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 { @@ -14090,8 +13991,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 2026-04-08 18:03:31.588010588 +0000 -@@ -0,0 +1,1128 @@ ++++ b/arch/arm64/boot/dts/aspeed/ast2700-fpga.dts 2025-12-23 10:16:06.862271766 +0000 +@@ -0,0 +1,1132 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/dts-v1/; @@ -14770,6 +14671,10 @@ 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 { @@ -15222,8 +15127,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 2026-04-08 18:03:31.588010588 +0000 -@@ -0,0 +1,48 @@ ++++ b/arch/arm64/boot/dts/aspeed/ast2700-ncsi.dts 2025-12-23 10:16:06.862271766 +0000 +@@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/dts-v1/; @@ -15271,10 +15176,14 @@ 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 2026-04-08 18:03:31.588010588 +0000 ++++ b/arch/arm64/boot/dts/aspeed/ast2700-raw.dts 2025-12-23 10:16:06.862271766 +0000 @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + @@ -15498,8 +15407,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 2026-04-08 18:03:31.588010588 +0000 -@@ -0,0 +1,128 @@ ++++ b/arch/arm64/boot/dts/aspeed/ast2700-reserved-mem.dtsi 2025-12-23 10:16:06.862271766 +0000 +@@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* AST2700 reserved memories with no-map property */ @@ -15528,7 +15437,6 @@ 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; +}; @@ -15547,7 +15455,6 @@ 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; +}; @@ -15630,8 +15537,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 2026-04-08 18:03:31.588010588 +0000 -@@ -0,0 +1,844 @@ ++++ b/arch/arm64/boot/dts/aspeed/ast2700-slt.dts 2025-12-23 10:16:06.862271766 +0000 +@@ -0,0 +1,857 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/dts-v1/; @@ -16199,6 +16106,19 @@ 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>; @@ -16476,59193 +16396,50579 @@ diff --git a/arch/arm64/boot/dts/aspeed/ast2700-slt.dts b/arch/arm64/boot/dts/as +&otp { + status = "okay"; +}; -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-04-08 18:03:31.588010588 +0000 -@@ -0,0 +1,127 @@ +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 @@ +// SPDX-License-Identifier: GPL-2.0-or-later ++// Copyright ASPEED Technology + -+/dts-v1/; ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+#include "ast2700a1-evb.dts" ++#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) + -+/ { -+ model = "AST2700A1-CI-HOST"; -+}; ++#define LTPI_LINK_CONTROLL 0x80 ++#define LTPI_AUTO_CONFIG BIT(10) + -+&bmc_dev0 { -+ status = "disabled"; -+}; ++#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) + -+&xdma0 { -+ status = "disabled"; -+}; ++#define LTPI_MANUAL_CAP_LOW 0x118 ++#define LTPI_MANUAL_CAP_HIGH 0x11c + -+&pcie_vuart0 { -+ status = "disabled"; -+}; ++#define LTPI_I2C_TIMING_0 0x134 ++#define LTPI_I2C_TIMING_1 0x138 + -+&pcie_vuart1 { -+ status = "disabled"; -+}; ++#define LTPI_I2C_100K_0 0x3535352f ++#define LTPI_I2C_100K_1 0x09353535 + -+&pcie_lpc0_kcs0 { -+ status = "disabled"; -+}; ++#define LTPI_I2C_400K_0 0x06060d06 ++#define LTPI_I2C_400K_1 0x090d0a06 + -+&pcie_lpc0_kcs1 { -+ 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_kcs2 { -+ status = "disabled"; -+}; ++#define MAX_I2C_IN_LTPI 6 ++#define MAX_UART_IN_LTPI 2 + -+&pcie_lpc0_kcs3 { -+ status = "disabled"; ++enum chip_version { ++ AST2700, ++ AST1700, +}; + -+&pcie_lpc0_ibt { -+ 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; +}; + -+&pcie0_mmbi0 { -+ 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 { -+ status = "okay"; -+}; ++ 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 */ ++ } + -+&bmc_dev1 { -+ status = "disabled"; -+}; ++ writel(status, priv->regs + LTPI_INTR_STATUS); + -+&xdma1 { -+ status = "disabled"; -+}; ++ return IRQ_HANDLED; ++} + -+&pcie_vuart2 { -+ status = "disabled"; -+}; ++static int aspeed_ltpi_init_mux(struct aspeed_ltpi_priv *priv) ++{ ++ u32 reg, i2c_en, uart_en, i; + -+&pcie_vuart3 { -+ status = "disabled"; -+}; ++ reg = readl(priv->regs + LTPI_AUTO_CAP_LOW); + -+&pcie_lpc1_kcs0 { -+ status = "disabled"; -+}; ++ i2c_en = FIELD_GET(LTPI_I2C_IO_FRAME_EN, reg); ++ i2c_en &= priv->i2c_tunneling; + -+&pcie_lpc1_kcs1 { -+ 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_kcs2 { -+ status = "disabled"; -+}; ++ reg = readl(priv->regs + LTPI_AUTO_CAP_HIGH); + -+&pcie_lpc1_kcs3 { -+ status = "disabled"; -+}; ++ uart_en = FIELD_GET(LTPI_UART_IO_FRAME_EN, reg); ++ uart_en &= priv->uart_tunneling; + -+&pcie_lpc1_ibt { -+ status = "disabled"; -+}; ++ reg &= ~LTPI_UART_IO_FRAME_EN; ++ reg |= FIELD_PREP(LTPI_UART_IO_FRAME_EN, uart_en); + -+&pcie1_mmbi4 { -+ status = "disabled"; -+}; ++ writel(reg, priv->regs + LTPI_MANUAL_CAP_HIGH); + -+&pcie1 { -+ status = "okay"; -+}; ++ /* Apply LTPI manual configuration */ ++ reg = readl(priv->regs + LTPI_LINK_CONTROLL); ++ reg &= ~LTPI_AUTO_CONFIG; ++ writel(reg, priv->regs + LTPI_LINK_CONTROLL); + -+&mdio0 { -+ status = "disabled"; -+}; ++ /* 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)); ++ } ++ } ++ } + -+&mac0 { -+ status = "disabled"; -+}; ++ return 0; ++} + -+&mdio2 { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; ++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; + -+ ethphy2: ethernet-phy@0 { -+ compatible = "ethernet-phy-ieee802.3-c22"; -+ reg = <0>; -+ }; -+}; ++ match = of_match_device(dev->driver->of_match_table, dev); + -+&sgmii { -+ status = "okay"; -+}; ++ if (match) { ++ if (of_property_match_string(np, "compatible", match->compatible) < 0) ++ return -ENODEV; ++ } else { ++ return -ENODEV; ++ } + -+&mac2 { -+ status = "okay"; ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; + -+ 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-04-08 18:03:31.588010588 +0000 -@@ -0,0 +1,974 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later ++ priv->dev = dev; ++ priv->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(priv->regs)) ++ return PTR_ERR(priv->regs); + -+/dts-v1/; ++ priv->version = (enum chip_version)device_get_match_data(dev); + -+#include "aspeed-g7.dtsi" -+#include -+#include ++ 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); + -+#define PCIE0_EP 1 // 1: EP, 0: RC -+#define PCIE1_EP 1 // 1: EP, 0: RC ++ clk_prepare_enable(priv->ltpi_clk); + -+/ { -+ model = "AST2700A1-DCSCM"; -+ compatible = "aspeed,ast2700"; ++ priv->ltpi_phyclk = devm_clk_get(&pdev->dev, "phy"); ++ if (IS_ERR(priv->ltpi_phyclk)) ++ return PTR_ERR(priv->ltpi_phyclk); + -+ chosen { -+ stdout-path = "serial12:115200n8"; -+ }; ++ clk_prepare_enable(priv->ltpi_phyclk); ++ } else { ++ priv->ltpi_phyclk = NULL; ++ } + -+ memory@400000000 { -+ device_type = "memory"; -+ reg = <0x4 0x00000000 0x0 0x40000000>; -+ }; ++ priv->ltpi_rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); ++ if (IS_ERR(priv->ltpi_rst)) ++ return PTR_ERR(priv->ltpi_rst); + -+ reserved-memory { -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges; ++ reset_control_deassert(priv->ltpi_rst); + -+ #include "ast2700-reserved-mem.dtsi" ++ priv->i2c_tunneling = GENMASK(MAX_I2C_IN_LTPI - 1, 0); ++ if (!of_property_read_u32(np, "i2c-tunneling", &ret)) ++ priv->i2c_tunneling = ret; + -+ video_engine_memory0: video0 { -+ size = <0x0 0x02000000>; -+ alignment = <0x0 0x00010000>; -+ compatible = "shared-dma-pool"; -+ reusable; -+ }; ++ 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_memory1: video1{ -+ 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; + -+#if 0 -+ gfx_memory: framebuffer { -+ size = <0x0 0x01000000>; -+ alignment = <0x0 0x01000000>; -+ compatible = "shared-dma-pool"; -+ reusable; -+ }; -+#endif -+ }; ++ /* 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); + -+ iio-hwmon { -+ compatible = "iio-hwmon"; -+ io-channels = <&adc0 7>, <&adc1 7>; -+ }; -+}; ++ regmap_read(priv->scu, SCU_IO_OTP_TRAP1, ®); ++ regmap_write(priv->scu, SCU_IO_OTP_TRAP1_CLEAR, reg); + -+&pwm_tach { -+ status = "okay"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_pwm9_default>; -+}; ++ 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; ++ } + -+&adc0 { -+ aspeed,int-vref-microvolt = <2500000>; -+ status = "okay"; -+ aspeed,battery-sensing; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_adc7_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); ++ } + -+&adc1 { -+ aspeed,int-vref-microvolt = <2500000>; -+ status = "okay"; -+ aspeed,battery-sensing; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_adc15_default>; -+}; ++ aspeed_ltpi_init_mux(priv); + -+&pinctrl1 { -+ pinctrl_i3c0_3_hv_voltage: i3chv-voltage { -+ pins = "U25"; -+ power-source = <1800>; -+ }; ++ platform_set_drvdata(pdev, priv); ++ if (np) ++ of_platform_populate(np, NULL, lookup, priv->dev); + -+ pinctrl_i3c0_driving: i3c0-driving { -+ pins = "U25", "U26"; -+ drive-strength = <2>; -+ }; -+ -+ pinctrl_i3c1_driving: i3c1-driving { -+ pins = "Y26", "AA24"; -+ drive-strength = <2>; -+ }; ++ return 0; ++} + -+ pinctrl_i3c2_driving: i3c2-driving { -+ pins = "R25", "AA26"; -+ drive-strength = <2>; -+ }; ++static void aspeed_ltpi_remove(struct platform_device *pdev) ++{ ++ struct aspeed_ltpi_priv *priv; + -+ pinctrl_i3c3_driving: i3c3-driving { -+ pins = "R26", "Y25"; -+ 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_rgmii0_driving: rgmii0-driving { -+ pins = "C20", "C19", "A8", "R14", "A7", "P14", -+ "D20", "A6", "B6", "N14", "B7", "B8"; -+ drive-strength = <1>; -+ }; ++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); + -+&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"; ++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, ++ }, +}; + -+&i3c1 { -+ /* BMC_I2C_I3C1_SCL1 */ -+ initial-role = "primary"; -+ status = "okay"; -+}; ++module_platform_driver(aspeed_ltpi_driver); + -+&i3c2 { -+ /* BMC_I2C_I3C2_SCL2 */ -+ initial-role = "primary"; -+ status = "okay"; -+}; ++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 +@@ -286,6 +286,7 @@ + config HW_RANDOM_NOMADIK + tristate "ST-Ericsson Nomadik Random Number Generator support" + depends on ARCH_NOMADIK || COMPILE_TEST ++ depends on ARM_AMBA + default HW_RANDOM + help + This driver provides kernel-side support for the Random Number +@@ -587,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. + -+&i3c3 { -+ /* I3C_DBG_SCM */ -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ To compile this driver as a module, choose M here: the ++ module will be called aspeed-rng. + -+/* AST2700 i3c4 -> AST1060 i3c2 for MCTP over I3C. */ -+&i3c4 { -+ /* I3C_PFR_BMC */ -+ initial-role = "target"; -+ pid = <0x000007ec 0x06000000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ If unsure, say Y. + -+&i3c5 { -+ /* I3C_MNG_BMC_SCM */ -+ initial-role = "primary"; -+ status = "okay"; -+}; ++source "drivers/char/hw_random/dwc/Kconfig" + -+&i3c6 { -+ /* I3C_SPD_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. ++ */ + -+/* Enable UART2 and UART9 for obmc-console. */ -+&uart2 { -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+&uart9 { -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; ++#define TRNG_CTL 0x00 ++#define TRNG_EN 0x0 ++#define TRNG_MODE 0x04 ++#define TRNG_RDY 0x1f ++#define TRNG_ODATA 0x04 + -+/* Enable UART7 and UART10 for obmc-console. */ -+&uart7 { -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ 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; +}; + -+&uart10 { -+ /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; + -+/* UART3, UART13 and UART14 will be tunnelded to LTPI UART channels. */ -+&uart3 { -+ /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; ++ } ++ } + -+&uart13 { -+ status = "okay"; -+}; ++ return read; ++} + -+&uart14 { -+ status = "okay"; -+}; ++static void aspeed_trng_enable(struct aspeed_trng *priv) ++{ ++ u32 ctl; + -+&uart12 { -+ status = "okay"; -+}; ++ ctl = readl(priv->base + TRNG_CTL); ++ ctl = ctl & ~(1 << TRNG_EN); /* enable rng */ ++ ctl = ctl | (3 << TRNG_MODE); /* select mode */ + -+&fmc { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_fwspi_quad_default>; -+ pinctrl-names = "default"; ++ writel(ctl, priv->base + TRNG_CTL); ++} + -+ 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"; -+ }; -+ }; -+ }; -+}; ++static void aspeed_trng_disable(struct aspeed_trng *priv) ++{ ++ writel(1, priv->base + TRNG_CTL); ++} + -+&spi0 { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_spi0_default &pinctrl_spi0_cs1_default>; -+ pinctrl-names = "default"; ++static int aspeed_trng_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct aspeed_trng *priv; ++ struct resource *res; ++ int ret; + -+ 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"; -+ }; -+ }; -+ }; ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; + -+ flash@1 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "spi0:1"; -+ spi-max-frequency = <12500000>; -+ spi-tx-bus-width = <1>; -+ spi-rx-bus-width = <1>; -+ }; -+}; ++ 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); + -+&spi1 { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_spi1_default &pinctrl_spi1_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 = "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>; ++ aspeed_trng_enable(priv); + -+ spi1_pch_reserved@0 { -+ reg = <0x0 0x7f0000>; -+ label = "spi1_pch_reserved"; -+ }; ++ ret = devm_hwrng_register(&pdev->dev, &priv->rng); ++ if (ret) ++ return ret; + -+ spi1_pch_stg@7f0000 { -+ reg = <0x7f0000 0x1400000>; -+ label = "spi1_pch_stg"; -+ }; ++ platform_set_drvdata(pdev, priv); + -+ spi1_pch_rc@1bf0000 { -+ reg = <0x1bf0000 0x1400000>; -+ label = "spi1_pch_rc"; -+ }; ++ dev_info(dev, "Aspeed Hardware RNG successfully registered\n"); + -+ spi1_pch_pfm@2ff0000 { -+ reg = <0x2ff0000 0x10000>; -+ label = "spi1_pch_pfm"; -+ }; ++ return 0; ++} + -+ spi1_pch_bios@3000000 { -+ reg = <0x3000000 0x1000000>; -+ label = "spi1_pch_bios"; -+ }; -+ }; -+ }; ++static void aspeed_trng_remove(struct platform_device *pdev) ++{ ++ struct aspeed_trng *priv = platform_get_drvdata(pdev); + -+ flash@1 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "spi1:1"; -+ spi-max-frequency = <12500000>; -+ spi-tx-bus-width = <1>; -+ spi-rx-bus-width = <1>; -+ }; -+}; ++ aspeed_trng_disable(priv); ++} + -+<pi0 { -+ status = "okay"; ++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); + -+<pi1 { -+ /* Do not tunnel I2C10 to the HPM */ -+ i2c-tunneling = <0x2f>; -+ status = "okay"; ++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, ++ }, +}; + -+/* 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*/ "","","","","","","",""; ++module_platform_driver(aspeed_trng_driver); + -+ 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"; -+ }; -+}; ++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 ++# + -+&peci0 { -+ 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. + -+&chassis { -+ status = "okay"; -+}; ++ To compile this driver as a module, choose M here. the ++ module will be called dwc-rng. + -+&mdio0 { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; ++ If unsure, say Y. + -+ ethphy0: ethernet-phy@0 { -+ compatible = "ethernet-phy-ieee802.3-c22"; -+ reg = <0>; -+ }; -+}; +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 + -+&mac0 { -+ 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 + -+ phy-mode = "rgmii-id"; -+ phy-handle = <ðphy0>; ++obj-$(CONFIG_HW_RANDOM_DWC) += elppdu.o ++elppdu-objs := src/pdu/linux/kernel/pdu.o \ ++ src/pdu/common/pdu/pdu_dev32.o \ + -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_rgmii0_default &pinctrl_rgmii0_driving>; -+}; ++obj-$(CONFIG_HW_RANDOM_DWC) += elpmem.o ++elpmem-objs := src/pdu/linux/kernel/spacc_mem.o \ + -+&jtag1 { -+ status = "okay"; -+}; ++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 \ + -+&gpio1 { -+ pinctrl-0 = <&pinctrl_i3c0_3_hv_voltage -+ &pinctrl_i3c0_driving &pinctrl_i3c1_driving -+ &pinctrl_i3c2_driving &pinctrl_i3c3_driving>; -+ pinctrl-names = "default"; ++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. ++ */ + -+ 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*/ "","","","","","","",""; -+}; ++#ifndef SYNPDU_ERROR_H_ ++#define SYNPDU_ERROR_H_ + -+/* 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*/ "","","","","","","",""; -+}; ++/* ++ * Common error definitions. Be sure to update pdu_error_code when changing ++ * anything in this list. ++ */ + -+&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; -+}; ++#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) + -+#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 +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. ++ */ + -+&lpc0_kcs0 { -+ status = "okay"; -+ kcs-io-addr = <0xca0>; -+ kcs-channel = <0>; -+}; -+ -+&lpc0_kcs1 { -+ status = "okay"; -+ kcs-io-addr = <0xca8>; -+ kcs-channel = <1>; -+}; ++#include "elppdu.h" + -+&lpc0_kcs2 { -+ status = "okay"; -+ kcs-io-addr = <0xca2>; -+ kcs-channel = <2>; -+}; ++void pdu_to_dev32(void *addr_, u32 *src, unsigned long nword) ++{ ++ unsigned char *addr = addr_; + -+&lpc0_kcs3 { -+ status = "okay"; -+ kcs-io-addr = <0xca4>; -+ kcs-channel = <3>; -+}; ++ while (nword--) { ++ pdu_io_write32(addr, *src++); ++ addr += 4; ++ } ++} ++EXPORT_SYMBOL(pdu_to_dev32); + -+&lpc0_ibt { -+ status = "okay"; -+}; ++void pdu_from_dev32(u32 *dst, void *addr_, unsigned long nword) ++{ ++ unsigned char *addr = addr_; + -+&lpc0_mbox { -+ status = "okay"; -+}; ++ while (nword--) { ++ *dst++ = pdu_io_read32(addr); ++ addr += 4; ++ } ++} ++EXPORT_SYMBOL(pdu_from_dev32); + -+&lpc0_snoop { -+ status = "okay"; -+ snoop-ports = <0x80>, <0x81>; -+}; ++void pdu_to_dev32_big(void *addr_, const unsigned char *src, ++ unsigned long nword) ++{ ++ unsigned char *addr = addr_; ++ unsigned long v; + -+&lpc0_uart_routing { -+ status = "okay"; -+}; ++ 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); + -+&lpc1_kcs0 { -+ status = "okay"; -+ kcs-io-addr = <0xca0>; -+ kcs-channel = <4>; -+}; ++void pdu_from_dev32_big(unsigned char *dst, void *addr_, unsigned long nword) ++{ ++ unsigned char *addr = addr_; ++ unsigned long v; + -+&lpc1_kcs1 { -+ status = "okay"; -+ kcs-io-addr = <0xca8>; -+ kcs-channel = <5>; -+}; ++ 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); + -+&lpc1_kcs2 { -+ status = "okay"; -+ kcs-io-addr = <0xca2>; -+ kcs-channel = <6>; -+}; ++void pdu_to_dev32_little(void *addr_, const unsigned char *src, ++ unsigned long nword) ++{ ++ unsigned char *addr = addr_; ++ unsigned long v; + -+&lpc1_kcs3 { -+ status = "okay"; -+ kcs-io-addr = <0xca4>; -+ kcs-channel = <7>; -+}; ++ 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); + -+&lpc1_ibt { -+ status = "okay"; -+}; ++void pdu_from_dev32_little(unsigned char *dst, void *addr_, unsigned long nword) ++{ ++ unsigned char *addr = addr_; ++ unsigned long v; + -+&lpc1_mbox { -+ status = "okay"; -+}; ++ 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); + -+&lpc1_snoop { -+ status = "okay"; -+ snoop-ports = <0x80>, <0x81>; -+}; ++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); + -+&lpc1_uart_routing { -+ 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. ++ */ + -+&video0 { -+ status = "okay"; -+ memory-region = <&video_engine_memory0>; -+}; ++#ifndef SYNPDU_H_ ++#define SYNPDU_H_ + -+&video1 { -+ status = "okay"; -+ memory-region = <&video_engine_memory1>; -+}; ++/* Platform Specific */ ++#include /* printk() */ ++#include /* size_t */ ++#include /* memcpy()/etc */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+&disp_intf { -+ status = "okay"; -+}; ++#ifndef PDU_BASE_ADDR ++#define PDU_BASE_ADDR 0x14c3b000 ++#endif + -+&rtc { -+ status = "okay"; -+}; ++#ifndef PDU_BASE_IRQ ++#define PDU_BASE_IRQ 91 ++#endif + -+&rsss { -+ status = "okay"; -+}; ++#define PDU_SINGLE_CORE 1 ++#define PDU_SINGLE_NIST_TRNG 1 + -+&ecdsa { -+ status = "okay"; -+}; ++#if 1 ++#define SYNHW_PRINT printk ++#else ++#define SYNHW_PRINT(...) ++#endif + -+&hace { -+ status = "okay"; -+}; ++#define CPU_YIELD ++#define SYNHW_MEMCPY memcpy + -+&bmc_dev0 { -+ status = "okay"; -+ memory-region = <&bmc_dev0_memory>; -+}; ++// 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 + -+&xdma0 { -+ status = "okay"; -+ memory-region = <&xdma_memory0>; -+}; ++// Locking ++#define PDU_LOCK_TYPE spinlock_t ++#define PDU_INIT_LOCK(lock) spin_lock_init(lock) + -+&pcie_vuart0 { -+ port = <0x3f8>; -+ sirq = <4>; -+ sirq-polarity = <0>; ++// 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) + -+ status = "okay"; -+}; ++// 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) + -+&pcie_vuart1 { -+ port = <0x2f8>; -+ sirq = <3>; -+ sirq-polarity = <0>; ++#include "../../common/include/elppdu_error.h" + -+ status = "okay"; -+}; ++void *pdu_linux_map_regs(struct device *dev, struct resource *regs); + -+&pcie_lpc0_kcs0 { -+ status = "okay"; -+ kcs-io-addr = <0x3a0>; -+ kcs-channel = <8>; -+}; ++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); + -+&pcie_lpc0_kcs1 { -+ status = "okay"; -+ kcs-io-addr = <0x3a8>; -+ kcs-channel = <9>; -+}; ++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); + -+&pcie_lpc0_kcs2 { -+ status = "okay"; -+ kcs-io-addr = <0x3a2>; -+ kcs-channel = <10>; -+}; ++void *pdu_malloc(unsigned long n); ++void pdu_free(void *p); + -+&pcie_lpc0_kcs3 { -+ status = "okay"; -+ kcs-io-addr = <0x3a4>; -+ kcs-channel = <11>; -+}; ++int pdu_error_code(int code); + -+&pcie_lpc0_ibt { -+ status = "okay"; -+ bt-channel = <2>; -+}; ++#endif + -+&bmc_dev1 { -+ status = "okay"; -+ memory-region = <&bmc_dev1_memory>; -+}; +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. ++ */ + -+&xdma1 { -+ status = "okay"; -+ memory-region = <&xdma_memory1>; -+}; ++#include + -+&pcie_vuart2 { -+ port = <0x3f8>; -+ sirq = <4>; -+ sirq-polarity = <0>; ++#include "elppdu.h" + -+ status = "okay"; -+}; ++static bool trace_io; ++module_param(trace_io, bool, 0600); ++MODULE_PARM_DESC(trace_io, "Trace MMIO reads/writes"); + -+&pcie_vuart3 { -+ port = <0x2f8>; -+ sirq = <3>; -+ sirq-polarity = <0>; ++void *pdu_linux_map_regs(struct device *dev, struct resource *regs) ++{ ++ return devm_ioremap_resource(dev, regs); ++} ++EXPORT_SYMBOL(pdu_linux_map_regs); + -+ status = "okay"; -+}; ++void pdu_io_write32(void *addr, unsigned long val) ++{ ++ if (trace_io) ++ SYNHW_PRINT("PDU: write %.8lx -> %p\n", val, addr); + -+&pcie_lpc1_kcs0 { -+ status = "okay"; -+ kcs-io-addr = <0x3a0>; -+ kcs-channel = <12>; -+}; ++ writel(val, addr); ++} ++EXPORT_SYMBOL(pdu_io_write32); + -+&pcie_lpc1_kcs1 { -+ status = "okay"; -+ kcs-io-addr = <0x3a8>; -+ kcs-channel = <13>; -+}; ++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_lpc1_kcs2 { -+ status = "okay"; -+ kcs-io-addr = <0x3a2>; -+ kcs-channel = <14>; -+}; ++ *cache = val; ++ pdu_io_write32(addr, val); ++} ++EXPORT_SYMBOL(pdu_io_cached_write32); + -+&pcie_lpc1_kcs3 { -+ status = "okay"; -+ kcs-io-addr = <0x3a4>; -+ kcs-channel = <15>; -+}; ++unsigned long pdu_io_read32(void *addr) ++{ ++ unsigned long val; + -+&pcie_lpc1_ibt { -+ status = "okay"; -+ bt-channel = <3>; -+}; ++ val = readl(addr); + -+&mctp0 { -+ status = "okay"; -+ memory-region = <&mctp0_reserved>; -+}; ++ if (trace_io) ++ SYNHW_PRINT("PDU: read %.8lx <- %p\n", val, addr); + -+&mctp1 { -+ status = "okay"; -+ memory-region = <&mctp1_reserved>; -+}; ++ return val; ++} ++EXPORT_SYMBOL(pdu_io_read32); + -+/* Enable i2c0~i2c4 for LTPI testing. */ -+&i2c0 { -+ /* SMB_PMBUS1_SCM */ -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; ++/* Platform specific memory allocation */ ++void *pdu_malloc(unsigned long n) ++{ ++ return vmalloc(n); ++} + -+&i2c1 { -+ /* SMB_IPMB_SCL1 */ -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; ++void pdu_free(void *p) ++{ ++ vfree(p); ++} + -+&i2c2 { -+ /* SMB_CPLD_SCL2 */ -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ 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; ++ } + -+&i2c3 { -+ /* SMB_PMBUS2_SCM */ -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; ++ /* ++ * 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); + -+&i2c4 { -+ /* SMB_PMBUS1_SCM */ -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; ++static int __init pdu_mod_init(void) ++{ ++ return 0; ++} + -+/* Default i2c5 is tunnelded to LTPI. */ -+/* Enable i2c5 pinctrl for testing on board LM75. */ -+&i2c5 { -+ /* SMB_TMP_BMC */ -+ status = "okay"; -+}; ++static void __exit pdu_mod_exit(void) ++{ ++} + -+/* 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)>; -+ }; -+}; ++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. ++ */ + -+&i2c9 { -+ /* SMB_HOST_BMC */ -+ status = "okay"; -+ eeprom@50 { -+ compatible = "atmel,24c04"; -+ reg = <0x50>; -+ pagesize = <16>; -+ }; -+}; ++#include ++#include ++#include ++#include ++#include ++#include + -+/* 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)>; -+ }; -+}; ++#include "elppdu.h" + -+&i2c11 { -+ /* BMC_HPM_I3C_I2C_13 */ -+ status = "okay"; -+}; ++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) ")"); + -+&uphy3a { -+ status = "okay"; -+}; ++// max of 16 devices ++#define MAX_DEV 16 + -+&uphy3b { -+ status = "okay"; -+}; ++static struct platform_device *devices[MAX_DEV]; ++static int dev_id; + -+&vhuba0 { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_usb2ahpd0_default>; -+}; ++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, ++ }; + -+&usb3ahp { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_usb3axhp_default &pinctrl_usb2axhp_default>; -+}; ++ if (dev_id >= MAX_DEV) { ++ pr_err("Too many devices; increase MAX_DEV.\n"); ++ return; ++ } + -+&usb3bhp { -+ status = "okay"; -+}; -+ -+&uphy2b { -+ status = "okay"; -+}; -+ -+&vhubb1 { -+ status = "okay"; -+}; -+ -+&vhubc { -+ status = "okay"; -+}; -+ -+&ehci3 { -+ status = "okay"; -+}; -+ -+&uhci1 { -+ status = "okay"; -+ memory-region = <&uhci1_reserved>; -+}; ++ 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); + -+&wdt0 { -+ status = "okay"; -+}; ++ devices[dev_id] = NULL; ++ return; ++ } + -+&wdt1 { -+ status = "okay"; -+}; ++ dev_id++; ++} + -+&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 ---- 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-04-08 18:03:31.588010588 +0000 -@@ -0,0 +1,218 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later ++static int __init get_irq_num(unsigned int irq_num) ++{ ++ if (IS_ENABLED(CONFIG_ARCH_ZYNQ)) { ++ struct of_phandle_args args = { 0 }; + -+/dts-v1/; ++ /* ++ * 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. ++ */ + -+#include "ast2700a1-dcscm_ast1700a1-evb.dts" -+#include "aspeed-ltpi1.dtsi" ++ 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")); + -+/ { -+ model = "AST2700A1-DCSCM_AST1700A1-EVB-DUAL"; ++ if (irq_num < 32 || irq_num >= 96) { ++ pr_err("SPI interrupts must be in the range [32,96) on Zynq\n"); ++ return -EINVAL; ++ } + -+ 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>; -+ }; -+}; ++ args.args_count = 3; ++ args.args[0] = 0; /* SPI */ ++ args.args[1] = irq_num - 32; ++ args.args[2] = 4; /* Active high, level-sensitive */ + -+<pi1_adc0 { -+ aspeed,int-vref-microvolt = <2500000>; -+ status = "okay"; -+}; ++ irq_num = irq_create_of_mapping(&args); ++ of_node_put(args.np); ++ if (irq_num == 0) ++ return -EINVAL; ++ } + -+<pi1_adc1 { -+ aspeed,int-vref-microvolt = <2500000>; -+ status = "okay"; -+}; ++ if (irq_num > INT_MAX) ++ return -EINVAL; + -+<pi1 { -+ i2c-tunneling = <0x0>; -+ status = "okay"; -+}; ++ return irq_num; ++} + -+<pi1_gpio { -+ 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 + -+<pi1_i3c0 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06010000>; -+ dcr = /bits/ 8 <0xcc>; -+ 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); ++ } + -+<pi1_i3c1 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++#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 + -+<pi1_i3c2 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06012000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++#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 + -+<pi1_i3c3 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ return 0; ++} ++module_init(pdu_vex_mod_init); + -+<pi1_i3c4 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06014000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++static void __exit pdu_vex_mod_exit(void) ++{ ++ int i; + -+<pi1_i3c5 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ for (i = 0; i < MAX_DEV; i++) ++ platform_device_unregister(devices[i]); ++} ++module_exit(pdu_vex_mod_exit); + -+<pi1_i3c6 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06016000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++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. ++ */ + -+<pi1_i3c7 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++#ifndef NISTTRNG_H ++#define NISTTRNG_H + -+<pi1_i3c8 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06018000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++#include "synversion.h" ++#include "elppdu.h" ++#include "nisttrng_hw.h" ++#include "nisttrng_common.h" ++#include "nisttrng_private.h" + -+<pi1_i3c9 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++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. ++// ++// ------------------------------------------------------------------------ + -+<pi1_i3c10 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601A000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++#ifndef NISTTRNG_COMMON_H ++#define NISTTRNG_COMMON_H + -+<pi1_i3c11 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++#define NIST_TRNG_RETRY_MAX 5000000UL + -+<pi1_i3c12 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601C000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++#define NIST_DFLT_MAX_BITS_PER_REQ BIT(19) ++#define NIST_DFLT_MAX_REQ_PER_SEED BIT(48) + -+<pi1_i3c13 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++/* Do not change the following parameters */ ++#define NIST_TRNG_DFLT_MAX_REJECTS 10 + -+<pi1_i3c14 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601E000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++#define DEBUG(...) ++//#define DEBUG(...) printk(__VA_ARGS__) + -+<pi1_i3c15 { -+ initial-role = "primary"; -+ status = "okay"; ++enum nisttrng_sec_strength { ++ SEC_STRNT_AES128 = 0, ++ SEC_STRNT_AES256 = 1 +}; + -+&i2c6 { -+ status = "disabled"; ++enum nisttrng_drbg_arch { ++ AES128 = 0, ++ AES256 = 1 +}; + -+&i2c7 { -+ status = "disabled"; ++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 +}; + -+// The following I2C buses require enabling according to the ast2700-dcscm.dts. -+// i2c8 / i2c9 / i2c10 ++struct nist_trng_state { ++ u32 *base; + -+&i2c11 { -+ status = "disabled"; -+}; ++ /* 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; + -+<pi1_i2c0 { -+ status = "okay"; -+}; ++ struct { ++ unsigned int ext_enum, ++ ext_ver, ++ rel_num; ++ } corekit_rel; + -+<pi1_i2c1 { -+ status = "okay"; -+}; ++ struct { ++ unsigned int core_type, ++ bg8, ++ cdc_synch_depth, ++ background_noise, ++ edu_present, ++ aes_datapath, ++ aes_max_key_size, ++ personilzation_str; ++ } build_cfg0; + -+<pi1_i2c2 { -+ status = "okay"; -+}; ++ 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; + -+<pi1_i2c3 { -+ status = "okay"; -+}; ++ 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; + -+<pi1_i2c4 { -+ status = "okay"; -+}; ++ /* 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; + -+<pi1_i2c5 { -+ status = "okay"; ++ /* 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_i2c6 { -+ status = "okay"; -+}; ++#define nist_trng_zero_status(x) \ ++ memset(&((x)->status), 0, sizeof((x)->status)) + -+<pi1_i2c7 { -+ status = "okay"; -+}; ++#define DRBG_INSTANTIATED(cs) \ ++ ((((cs) == NIST_TRNG_STATE_INSTANTIATE) || \ ++ ((cs) == NIST_TRNG_STATE_RESEED) || \ ++ ((cs) == NIST_TRNG_STATE_GENERATE)) ? 1 : 0) + -+<pi1_i2c8 { -+ status = "okay"; -+}; ++#define REQ_SEC_STRENGTH_IS_VALID(sec_st) \ ++ ((((sec_st) > 0) && ((sec_st) <= 256)) ? 1 : 0) + -+<pi1_i2c9 { -+ status = "okay"; -+}; ++#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. ++ */ + -+<pi1_i2c10 { -+ status = "okay"; -+}; ++#ifndef NISTTRNG_HW_H ++#define NISTTRNG_HW_H + -+<pi1_i2c11 { -+ status = "okay"; -+}; ++/* HW related Parameters */ ++#define NIST_TRNG_RAND_BLK_SIZE_BITS 128 ++#define CHX_URUN_BLANK_AFTER_RESET 0x3 + -+<pi1_i2c12 { -+ status = "okay"; -+}; -+ -+<pi1_i2c13 { -+ status = "okay"; -+}; -+ -+<pi1_i2c14 { -+ 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 + -+<pi1_i2c15 { -+ status = "okay"; -+}; ++/* 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 + -+&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-04-08 18:03:31.588010588 +0000 -@@ -0,0 +1,456 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later ++/* 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 + -+/dts-v1/; ++#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 + -+#include "ast2700a1-dcscm.dts" -+#include "aspeed-ltpi0.dtsi" ++#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))) + -+/ { -+ model = "AST2700A1-DCSCM_AST1700A1-EVB"; ++/* 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 + -+ 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>; -+ }; ++/* 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 + -+ 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>; -+ }; ++#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))) + -+ 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>; -+ }; ++/* 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 + -+ 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>; -+ }; ++#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) + -+ 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>; -+ }; ++/*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 + -+ 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>; -+ }; ++#define _NIST_TRNG_EDU_RBC_CTRL_CH_RATE_MASK 0xFUL ++#define _NIST_TRNG_EDU_RBC_CTRL_CH_URUN_BLANK_MASK 0x3UL + -+ 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>; -+ }; ++#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))) + -+ 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>; -+ }; ++#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))) + -+ 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>; -+ }; ++#define NISTTRNG_EDU_RBC_CTRL_GET_CH_RATE_AFTER_RESET 0x0 ++#define NISTTRNG_EDU_RBC_CTRL_SET_CH_URUN_BLANK_AFTER_RESET 0x3 + -+ 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>; -+ }; ++/* 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 + -+ 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>; -+ }; ++#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) + -+ 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>; -+ }; ++/* 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 + -+ 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>; -+ }; ++#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) + -+ 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>; -+ }; ++/* 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 + -+ 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>; -+ }; ++#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) + -+ 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>; -+ }; ++/*EDU_STAT*/ + -+ 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>; -+ }; -+}; ++#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) + -+<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>; -+ }; -+}; ++/* 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 + -+&sgpios { -+ /delete-property/ gpio-line-names; -+}; ++#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) + -+<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; -+}; ++/* 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 + -+<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>; -+}; ++#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) + -+<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>; -+}; ++/*EDU_ISTAT*/ + -+<pi0 { -+ i2c-tunneling = <0x0>; -+ status = "okay"; -+}; ++#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 + -+<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"; -+}; ++#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) + -+<pi0_i3c5 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++/* 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 + -+<pi0_i3c6 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06016000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++/* 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) + -+<pi0_i3c7 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++// 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) + -+<pi0_i3c8 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06018000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++/* 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) + -+<pi0_i3c9 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++/* 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) + -+<pi0_i3c10 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601A000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++/* 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) + -+<pi0_i3c11 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++/* 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) + -+<pi0_i3c12 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601C000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++#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 + -+<pi0_i3c13 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++#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) + -+<pi0_i3c14 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601E000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++#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) + -+<pi0_i3c15 { -+ initial-role = "primary"; -+ 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. ++ */ + -+&i2c0 { -+ status = "disabled"; -+}; ++#ifndef NISTTRNG_PRIVATE_H ++#define NISTTRNG_PRIVATE_H + -+&i2c1 { -+ status = "disabled"; -+}; ++#include "elppdu.h" ++#include "nisttrng_hw.h" ++#include "nisttrng_common.h" + -+&i2c2 { -+ status = "disabled"; -+}; ++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); + -+&i2c3 { -+ status = "disabled"; -+}; ++/* ---------- 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); + -+&i2c4 { -+ status = "disabled"; -+}; ++/* ---------- 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); + -+&i2c5 { -+ status = "disabled"; -+}; ++/* ---------- Load data APIs ---------- */ ++int nisttrng_load_ps_addin(struct nist_trng_state *state, void *input_str); + -+<pi0_i2c0 { -+ status = "okay"; -+}; ++/* ---------- 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); + -+<pi0_i2c1 { -+ status = "okay"; -+}; ++/* ---------- edu related ---------- */ + -+<pi0_i2c2 { -+ status = "okay"; -+}; ++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. ++ */ + -+<pi0_i2c3 { -+ status = "okay"; -+}; ++#ifndef VERSION_H ++#define VERSION_H + -+<pi0_i2c4 { -+ status = "okay"; -+}; ++#define TRNG_VERSION "1.00a" + -+<pi0_i2c5 { -+ 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. ++ */ + -+<pi0_i2c6 { -+ status = "okay"; -+}; ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+<pi0_i2c7 { -+ status = "okay"; -+}; ++#include ++#include + -+<pi0_i2c8 { -+ status = "okay"; -+}; ++#include "nisttrng.h" + -+<pi0_i2c9 { -+ status = "okay"; -+}; ++#define SYNOPSYS_HWRNG_DRIVER_NAME "hwrng-nist_trng" + -+<pi0_i2c10 { -+ status = "okay"; -+}; ++#define num_gen_bytes 64 ++static unsigned long max_reads = 128; + -+<pi0_i2c11 { -+ status = "okay"; ++struct synopsys_nisttrng_driver { ++ struct nist_trng_state nisttrng; ++ void *hwrng_drv; ++ void *crypto_drv; ++ unsigned char rand_out[num_gen_bytes]; +}; + -+<pi0_i2c12 { -+ status = "okay"; -+}; ++static unsigned int xxd_vtrng; + -+<pi0_i2c13 { -+ status = "okay"; -+}; ++static void nisttrng_reinit(struct nist_trng_state *nist_trng) ++{ ++ int err; + -+<pi0_i2c14 { -+ status = "okay"; -+}; ++ err = nisttrng_uninstantiate(nist_trng); ++ if (err && err != CRYPTO_NOT_INSTANTIATED) ++ goto ERR; + -+<pi0_i2c15 { -+ status = "okay"; -+}; ++ err = nisttrng_instantiate(nist_trng, 128, 1, NULL); ++ if (err) ++ goto ERR; + -+&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-04-08 18:03:31.588010588 +0000 -@@ -0,0 +1,436 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later ++ERR: ++ DEBUG("NIST_TRNG: Trying to reinitialize after a fatal alarm: %d\n", ++ err); ++} + -+/dts-v1/; ++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; + -+#include "ast2700a1-dcscm.dts" -+#include "aspeed-ltpi1800.dtsi" ++ if (!out) { ++ SYNHW_PRINT("memory not allocated\n"); ++ return -1; ++ } + -+/ { -+ model = "AST2700A1-DCSCM_AST1800-EVB"; ++ if (!pdev || !buf || !max) ++ return nisttrng_error; + -+ 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>; -+ }; ++ data = platform_get_drvdata(pdev); ++ if (data == 0) ++ return nisttrng_error; + -+ 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>; -+ }; ++ 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); + -+ 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>; -+ }; ++ return nisttrng_error; ++ } + -+ 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>; -+ }; ++ memcpy(buf, out, max); ++ kfree(out); + -+ 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>; -+ }; ++ return max; ++} + -+ 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 int nisttrng_hwrng_driver_read(struct hwrng *rng, void *buf, size_t max, ++ bool wait) ++{ ++ struct platform_device *pdev = 0; + -+ 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>; -+ }; ++ if (rng == 0) ++ return -1; + -+ 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>; -+ }; ++ pdev = (struct platform_device *)rng->priv; ++ return nisttrng_platform_driver_read(pdev, buf, max, wait); ++} + -+ 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>; -+ }; ++static ssize_t ckr_show(struct device *dev, struct device_attribute *devattr, ++ char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); + -+ 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>; -+ }; ++ 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); ++} + -+ 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>; -+ }; ++static ssize_t features_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); + -+ 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>; -+ }; ++ 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); ++} + -+ 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>; -+ }; ++static ssize_t secure_show(struct device *dev, struct device_attribute *devattr, ++ char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); + -+ 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>; -+ }; ++ 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_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>; -+ }; ++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_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>; -+ }; ++ ret = nisttrng_set_secure_mode(&priv->nisttrng, ++ sysfs_streq(buf, "on") ? 1 : 0); ++ if (ret) ++ return -1; + -+ 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>; -+ }; -+}; ++ return count; ++} + -+<pi0_jtag { -+ status = "okay"; -+}; ++static ssize_t nonce_show(struct device *dev, struct device_attribute *devattr, ++ char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); + -+<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>; -+ }; -+}; ++ return sprintf(buf, "%s\n", NIST_TRNG_REG_SMODE_GET_NONCE(pdu_io_read32(priv->nisttrng.base + ++ NIST_TRNG_REG_SMODE)) ? "on" : "off"); ++} + -+&sgpios { -+ /delete-property/ gpio-line-names; -+}; ++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; + -+<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; -+}; ++ ret = nisttrng_set_nonce_mode(&priv->nisttrng, ++ sysfs_streq(buf, "on") ? 1 : 0); ++ if (ret) ++ return -1; + -+<pi0_adc0 { -+ aspeed,int-vref-microvolt = <2500000>; -+ status = "okay"; -+}; ++ return count; ++} + -+<pi0_adc1 { -+ aspeed,int-vref-microvolt = <2500000>; -+ status = "okay"; -+}; ++static ssize_t sec_strength_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); + -+<pi0 { -+ i2c-tunneling = <0x0>; -+}; ++ return sprintf(buf, "%s\n", ++ priv->nisttrng.status.sec_strength ? "256" : "128"); ++} + -+<pi0_i3c0 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06010000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++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; + -+<pi0_i3c1 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ if (count > 8) ++ return -1; + -+<pi0_i3c2 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06012000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ foo[8] = 0; ++ memcpy(foo, buf, 8); ++ ret = kstrtoint(foo, 10, &tmp); ++ if (ret) ++ return ret; + -+<pi0_i3c3 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ ret = nisttrng_set_sec_strength(&priv->nisttrng, tmp); ++ if (ret) ++ return -1; + -+<pi0_i3c4 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06014000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ return count; ++} + -+<pi0_i3c5 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++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_i3c6 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06016000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ for (x = 0; x < 4; x++) { ++ sprintf(buf + 8 * x, "%08lx", ++ pdu_io_read32(priv->nisttrng.base + ++ NIST_TRNG_REG_RAND0 + 3 - x)); ++ } + -+<pi0_i3c7 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ strcat(buf, "\n"); ++ return strlen(buf); ++} + -+<pi0_i3c8 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06018000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++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_i3c9 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ 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_i3c10 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601A000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++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_i3c11 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ // string must be at least 12 32-bit words long in 0 padded hex ++ if (count < (2 * 12 * 4)) ++ return -1; + -+<pi0_i3c12 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601C000>; -+ 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_i3c13 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_SEED0 + x, ++ tmp); ++ } + -+<pi0_i3c14 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601E000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ return count; ++} + -+<pi0_i3c15 { -+ 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); + -+&i2c0 { -+ status = "disabled"; -+}; ++ for (x = 0; x < 16; x++) { ++ sprintf(buf + 8 * x, "%08lx", ++ pdu_io_read32(priv->nisttrng.base + ++ NIST_TRNG_REG_NPA_DATA0 + 15 - x)); ++ } + -+&i2c1 { -+ status = "disabled"; -+}; ++ strcat(buf, "\n"); ++ return strlen(buf); ++} + -+&i2c2 { -+ status = "disabled"; -+}; ++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; + -+&i2c3 { -+ status = "disabled"; -+}; ++ // string must be at least 16 32-bit words long in 0 padded hex ++ if (count < (2 * 16 * 4)) ++ return -1; + -+&i2c4 { -+ status = "disabled"; -+}; ++ foo[8] = 0; ++ for (x = 0; x < 16; x++) { ++ memcpy(foo, buf + x * 8, 8); ++ ret = kstrtouint(foo, 16, &tmp); ++ if (ret) ++ return ret; + -+&i2c5 { -+ status = "disabled"; -+}; ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_NPA_DATA0 + x, tmp); ++ } + -+<pi0_i2c0 { -+ status = "okay"; -+}; ++ return count; ++} + -+<pi0_i2c1 { -+ 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_i2c2 { -+ status = "okay"; -+}; ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_CTRL)); ++} + -+<pi0_i2c3 { -+ 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_i2c4 { -+ status = "okay"; -+}; ++ // string must be at least a 32-bit word in 0 padded hex ++ if (count < 8) ++ return -1; + -+<pi0_i2c5 { -+ status = "okay"; -+}; ++ foo[8] = 0; ++ memcpy(foo, buf, 8); ++ ret = kstrtouint(foo, 16, &tmp); ++ if (ret) ++ return ret; + -+<pi0_i2c6 { -+ status = "okay"; -+}; ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_CTRL, tmp); ++ return count; ++} + -+<pi0_i2c7 { -+ status = "okay"; -+}; ++static ssize_t istat_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_ISTAT)); ++} + -+<pi0_i2c9 { -+ status = "okay"; -+}; ++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; + -+<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_ISTAT, tmp); ++ return count; ++} + -+<pi0_i2c13 { -+ 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_i2c14 { -+ status = "okay"; -+}; ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_MODE)); ++} + -+<pi0_i2c15 { -+ 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; + -+&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-04-08 18:03:31.588010588 +0000 -@@ -0,0 +1,40 @@ -+// 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-evb.dts" ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_MODE, tmp); + -+&fmc { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_fwspi_quad_default>; -+ pinctrl-names = "default"; ++ return count; ++} + -+ 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" -+ }; ++static ssize_t smode_reg_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); + -+ flash@1 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "fmc0:1"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <4>; -+ spi-rx-bus-width = <4>; -+ }; ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_SMODE)); ++} + -+ flash@2 { -+ status = "disabled"; -+ m25p,fast-read; -+ label = "fmc0:2"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <4>; -+ spi-rx-bus-width = <4>; -+ }; -+}; ++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; + -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-04-08 18:03:31.588010588 +0000 -@@ -0,0 +1,367 @@ -+// 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; + -+#include "ast2700a1-evb.dts" -+#include ++ foo[8] = 0; ++ memcpy(foo, buf, 8); ++ ret = kstrtouint(foo, 16, &tmp); ++ if (ret) ++ return ret; + -+/ { -+ model = "AST2700A1 EVB Test S0 Test"; -+}; ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_SMODE, tmp); ++ return count; ++} + -+&pcie2 { -+ status = "disabled"; -+}; ++static ssize_t alarm_reg_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); + -+&mdio2 { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_ALARM)); ++} + -+ ethphy2: ethernet-phy@0 { -+ compatible = "ethernet-phy-ieee802.3-c22"; -+ reg = <0>; -+ }; -+}; ++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; + -+&sgmii { -+ status = "okay"; -+}; ++ // string must be at least a 32-bit word in 0 padded hex ++ if (count < 8) ++ return -1; + -+&mac2 { -+ status = "okay"; ++ foo[8] = 0; ++ memcpy(foo, buf, 8); ++ ret = kstrtouint(foo, 16, &tmp); ++ if (ret) ++ return ret; + -+ phy-mode = "sgmii"; -+ phy-handle = <ðphy2>; -+}; ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_ALARM, tmp); ++ return count; ++} + -+&sdio_controller { -+ status = "disabled"; -+}; ++static ssize_t stat_reg_show(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); + -+&sdhci { -+ status = "disabled"; -+}; ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_STAT)); ++} + -+&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; -+}; ++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; + -+&can0 { -+ status = "disabled"; -+}; ++ // string must be at least a 32-bit word in 0 padded hex ++ if (count < 8) ++ return -1; + -+// 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)>; -+ }; -+}; ++ foo[8] = 0; ++ memcpy(foo, buf, 8); ++ ret = kstrtouint(foo, 16, &tmp); ++ if (ret) ++ return ret; + -+&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)>; -+ }; -+}; ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_WDATA, tmp); ++ return count; ++} + -+&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)>; -+ }; -+}; ++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); + -+&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)>; -+ }; -+}; ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_IA_WDATA)); ++} + -+&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)>; -+ }; -+}; ++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); + -+&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)>; -+ }; -+}; ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_IA_RDATA)); ++} + -+&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)>; -+ }; -+}; ++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; + -+&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)>; -+ }; -+}; ++ // string must be at least a 32-bit word in 0 padded hex ++ if (count < 8) ++ return -1; + -+&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)>; -+ }; -+}; ++ foo[8] = 0; ++ memcpy(foo, buf, 8); ++ ret = kstrtouint(foo, 16, &tmp); ++ if (ret) ++ return ret; + -+&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)>; -+ }; -+}; ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_ADDR, tmp); ++ return count; ++} + -+&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)>; -+ }; -+}; ++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); + -+&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)>; -+ }; -+}; ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_IA_ADDR)); ++} + -+&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)>; -+ }; -+}; ++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; + -+&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)>; -+ }; -+}; ++ // string must be at least a 32-bit word in 0 padded hex ++ if (count < 8) ++ return -1; + -+&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)>; -+ }; -+}; ++ foo[8] = 0; ++ memcpy(foo, buf, 8); ++ ret = kstrtouint(foo, 16, &tmp); ++ if (ret) ++ return ret; + -+&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"; -+}; ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_CMD, tmp); ++ return count; ++} + -+&i3c1 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06011000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++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); + -+&i3c2 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06012000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_IA_CMD)); ++} + -+&i3c3 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06013000>; -+ dcr = /bits/ 8 <0xcc>; -+ 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); + -+&i3c4 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06014000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_EDU_RNC_CTRL)); ++} + -+&i3c5 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06015000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++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; + -+&i3c6 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06016000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ // string must be at least a 32-bit word in 0 padded hex ++ if (count < 8) ++ return -1; + -+&i3c7 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06017000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ foo[8] = 0; ++ memcpy(foo, buf, 8); ++ ret = kstrtouint(foo, 16, &tmp); ++ if (ret) ++ return ret; + -+&i3c8 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06018000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_EDU_RNC_CTRL, tmp); + -+&i3c9 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06019000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ return count; ++} + -+&i3c10 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601A000>; -+ 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); + -+&i3c11 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601B000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ return sprintf(buf, "%08lx\n", ++ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_EDU_RBC_CTRL)); ++} + -+&i3c12 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601C000>; -+ 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); + -+&i3c13 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601D000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ opts_str[4] = 0; ++ memcpy(opts_str, buf, 4); ++ ret = kstrtouint(opts_str, 16, &opts_int); ++ if (ret) ++ return ret; + -+&i3c14 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601E000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ SYNHW_PRINT("%s %x\n", __func__, opts_int); + -+&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-04-08 18:03:31.588010588 +0000 -@@ -0,0 +1,481 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later ++ enable = (opts_int >> 12 & 0xf); ++ if (enable > 1) { ++ SYNHW_PRINT("incorrect enable %x\n", enable); ++ return -1; ++ } + -+#include "ast2700a1-evb.dts" -+#include ++ 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; ++ } + -+/ { -+ model = "AST2700A1 EVB Test S1 Test"; -+}; ++ rate = (opts_int >> 4 & 0xf); ++ if (rate > 8) { ++ SYNHW_PRINT("incorrect rate %x\n", rate); ++ return -1; ++ } + -+&bmc_dev0 { -+ status = "disabled"; -+}; ++ urun_blnk = (opts_int & 0xf); ++ if (urun_blnk > 3) { ++ SYNHW_PRINT("incorrect urun_blnk %x\n", urun_blnk); ++ return -1; ++ } + -+&xdma0 { -+ status = "disabled"; -+}; ++ SYNHW_PRINT("enable %x rbc_num %x rate %x urun_blnk %x\n", enable, ++ rbc_num, rate, urun_blnk); + -+&pcie_vuart0 { -+ status = "disabled"; -+}; ++ ret = nisttrng_rbc(&priv->nisttrng, enable, rbc_num, rate, ++ urun_blnk); ++ if (ret) ++ return -1; + -+&pcie_vuart1 { -+ status = "disabled"; -+}; ++ return count; ++} + -+&pcie_lpc0_kcs0 { -+ 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; + -+&pcie_lpc0_kcs1 { -+ 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"); + -+&pcie_lpc0_kcs2 { -+ 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)); ++ } + -+&pcie_lpc0_kcs3 { -+ status = "disabled"; -+}; ++ tot_char += sprintf(buf + tot_char, "\n"); + -+&pcie_lpc0_ibt { -+ status = "disabled"; -+}; ++ return tot_char; ++} + -+&pcie0_mmbi0 { -+ 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; + -+&pcie0 { -+ status = "okay"; -+}; ++ // string must be at least a 32-bit word in 0 padded hex ++ if (count < 8) ++ return -1; + -+&bmc_dev1 { -+ status = "disabled"; -+}; ++ foo[8] = 0; ++ memcpy(foo, buf, 8); ++ ret = kstrtoul(foo, 16, &tmp); ++ if (ret) ++ return ret; + -+&xdma1 { -+ status = "disabled"; -+}; ++ ret = nisttrng_set_reminder_max_bits_per_req(&priv->nisttrng, ++ tmp); ++ if (ret) ++ return -1; + -+&pcie_vuart2 { -+ status = "disabled"; -+}; ++ return count; ++} + -+&pcie_vuart3 { -+ status = "disabled"; -+}; ++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); + -+&pcie_lpc1_kcs0 { -+ status = "disabled"; -+}; ++ return sprintf(buf, "%08lx\n", ++ priv->nisttrng.counters.max_bits_per_req); ++} + -+&pcie_lpc1_kcs1 { -+ status = "disabled"; -+}; ++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; + -+&pcie_lpc1_kcs2 { -+ status = "disabled"; -+}; ++ // string must be at least a 64-bit word in 0 padded hex ++ if (count < 16) ++ return -1; + -+&pcie_lpc1_kcs3 { -+ status = "disabled"; -+}; ++ foo[16] = 0; ++ memcpy(foo, buf, 16); ++ ret = kstrtoull(foo, 16, &tmp); ++ if (ret) ++ return ret; + -+&pcie_lpc1_ibt { -+ status = "disabled"; -+}; ++ ret = nisttrng_set_reminder_max_req_per_seed(&priv->nisttrng, ++ tmp); ++ if (ret) ++ return -1; + -+&pcie1_mmbi4 { -+ status = "disabled"; -+}; ++ return count; ++} + -+&pcie1 { -+ 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); + -+&sdio_controller { -+ status = "disabled"; -+}; ++ return sprintf(buf, "%08llx\n", ++ priv->nisttrng.counters.max_req_per_seed); ++} + -+&sdhci { -+ status = "disabled"; -+}; ++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; + -+&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; -+}; ++ t = NIST_TRNG_RETRY_MAX; + -+&can0 { -+ status = "disabled"; -+}; ++ // 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); + -+// 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)>; -+ }; -+}; ++ // 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); + -+&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)>; -+ }; -+}; ++ // 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; + -+&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)>; -+ }; -+}; ++ 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); + -+&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)>; -+ }; -+}; ++ 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)); ++ } + -+&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)>; -+ }; -+}; ++ // clear NOISE_RDY IRQ ++ DEBUG("Clear NOISE_RDY interrupt.\n"); ++ ret = nisttrng_wait_on_noise_rdy(&priv->nisttrng); ++ if (ret) ++ return -1; ++ } + -+&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)>; -+ }; -+}; ++ DEBUG("Wait for DONE\n"); ++ ret = nisttrng_wait_on_done(&priv->nisttrng); ++ if (ret) ++ return -1; + -+&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)>; -+ }; -+}; ++ strcat(buf, "\n"); ++ return strlen(buf); ++} + -+&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)>; -+ }; -+}; ++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; + -+&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)>; -+ }; -+}; ++ // generate entropy ++ ret = nisttrng_get_entropy_input(&priv->nisttrng, NULL, 0); ++ if (ret) ++ return -1; + -+&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)>; -+ }; -+}; ++ // 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; + -+&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)>; -+ }; -+}; ++ 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)); ++ } + -+&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)>; -+ }; -+}; ++ strcat(buf, "\n"); ++ return strlen(buf); ++} + -+&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)>; -+ }; -+}; ++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; + -+&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)>; -+ }; -+}; ++ if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES128) ++ rep = 2; ++ else if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES256) ++ rep = 3; + -+&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)>; -+ }; -+}; ++ DEBUG("Number of char in input = %zu\n", count); ++ if (count != (rep * 128)) ++ return -1; + -+&i3c0 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ 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; ++ } + -+&i3c1 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ ret = nisttrng_get_entropy_input(&priv->nisttrng, seed, 1); ++ if (ret) ++ return -1; + -+&i3c2 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ return count; ++} + -+&i3c3 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++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; + -+&i3c4 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES128) ++ rep = 2; ++ else if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES256) ++ rep = 3; + -+&i3c5 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ DEBUG("Number of char in input = %zu\n", count); ++ if (count != (rep * 32)) ++ return -1; + -+&i3c6 { -+ initial-role = "primary"; -+ 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; ++ } + -+&i3c7 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ ret = nisttrng_get_entropy_input(&priv->nisttrng, seed, 0); ++ if (ret) ++ return -1; + -+&i3c8 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ return count; ++} + -+&i3c9 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++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; + -+&i3c10 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ /* 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; + -+&i3c11 { -+ initial-role = "primary"; -+ 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; ++ } + -+&i3c12 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ if (opts_int & 1) ++ ps_exists = 1; ++ else ++ ps_exists = 0; + -+&i3c13 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ if (opts_int & 2) ++ req_sec_strength = 256; ++ else ++ req_sec_strength = 128; + -+&i3c14 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ if (opts_int & 4) ++ pred_resist = 1; ++ else ++ pred_resist = 0; + -+&i3c15 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ /* 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; ++ } ++ } + -+&sgpios { -+ status = "disabled"; -+}; ++ /* Personilization string */ ++ for (i = 0; i < 12; i++) ++ ps[i] = 0; + -+&mac0 { -+ status = "okay"; ++ if (req_sec_strength == 128) ++ ps_length = 64; ++ else if (req_sec_strength == 256) ++ ps_length = 96; ++ else ++ SYNHW_PRINT("Invalid security strength\n"); + -+ phy-mode = "rmii"; -+ use-ncsi; ++ if (ps_exists) { ++ opts_str[1] = 0; ++ memcpy(opts_str, buf + 3, 1); + -+ 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 (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"); ++ } + -+&mac1 { -+ status = "okay"; ++ ret = nisttrng_instantiate(&priv->nisttrng, ++ req_sec_strength, pred_resist, ++ ps); ++ if (ret) ++ return -1; + -+ phy-mode = "rmii"; -+ use-ncsi; ++ } else { ++ ret = nisttrng_instantiate(&priv->nisttrng, ++ req_sec_strength, pred_resist, ++ NULL); ++ if (ret) ++ return -1; ++ } + -+ 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>; -+}; ++ return count; ++} + -+&syscon1 { -+ mac0-clk-delay = <0 0 -+ 0 0 -+ 0 0>; -+ mac1-clk-delay = <0 0 -+ 0 0 -+ 0 0>; -+}; ++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); + -+&vhuba0 { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_usb2ad0_default>; -+}; ++ nisttrng_uninstantiate(&priv->nisttrng); + -+&uphy2a { -+ status = "okay"; -+}; ++ return count; ++} + -+&usb3ahp { -+ status = "disabled"; -+}; ++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; + -+&usb3bhp { -+ status = "disabled"; -+}; ++ /* 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; + -+&vhubb0 { -+ status = "okay"; -+}; ++ 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; ++ } + -+&vhubb1 { -+ status = "disabled"; -+}; ++ if (opts_int & 1) ++ addin_exists = 1; ++ else ++ addin_exists = 0; + -+&vhubc { -+ status = "disabled"; -+}; ++ if (opts_int & 2) ++ pred_resist = 1; ++ else ++ pred_resist = 0; + -+&vhubd { -+ 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; ++ } ++ } + -+&ehci2 { -+ status = "okay"; -+}; ++ /* Additional input */ ++ for (i = 0; i < 12; i++) ++ addin[i] = 0; + -+&ehci3 { -+ status = "disabled"; -+}; ++ 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"); + -+&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-04-08 18:03:31.588010588 +0000 -@@ -0,0 +1,1265 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later ++ if (addin_exists) { ++ opts_str[1] = 0; ++ memcpy(opts_str, buf + 2, 1); + -+/dts-v1/; -+#include "aspeed-g7.dtsi" -+#include -+#include -+#include ++ 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"); ++ } + -+#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"; ++ ret = nisttrng_reseed(&priv->nisttrng, pred_resist, ++ addin); ++ if (ret) ++ return -1; + -+ chosen { -+ stdout-path = "serial12:115200n8"; -+ }; ++ } else { ++ ret = nisttrng_reseed(&priv->nisttrng, pred_resist, ++ NULL); ++ if (ret) ++ return -1; ++ } + -+ memory@400000000 { -+ device_type = "memory"; -+ reg = <0x4 0x00000000 0x0 0x40000000>; -+ }; ++ return count; ++} + -+ reserved-memory { -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges; ++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; + -+ #include "ast2700-reserved-mem.dtsi" ++ /* 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; + -+ video_engine_memory0: video0 { -+ size = <0x0 0x02000000>; -+ alignment = <0x0 0x00010000>; -+ compatible = "shared-dma-pool"; -+ reusable; -+ }; ++ 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; ++ } + -+ video_engine_memory1: video1 { -+ size = <0x0 0x02000000>; -+ alignment = <0x0 0x00010000>; -+ compatible = "shared-dma-pool"; -+ reusable; -+ }; ++ if (opts_int & 1) ++ addin_exists = 1; ++ else ++ addin_exists = 0; + -+#if 0 -+ gfx_memory: framebuffer { -+ size = <0x0 0x01000000>; -+ alignment = <0x0 0x01000000>; -+ compatible = "shared-dma-pool"; -+ reusable; -+ }; -+#endif ++ if (opts_int & 2) ++ req_sec_strength = 256; ++ else ++ req_sec_strength = 128; + -+ espi0_mcyc_memory: mcyc0 { -+ size = <0x0 0x01000000>; -+ alignment = <0x0 0x00010000>; -+ compatible = "shared-dma-pool"; -+ reusable; -+ }; -+ }; ++ if (opts_int & 4) ++ pred_resist = 1; ++ else ++ pred_resist = 0; + -+ 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>; -+ }; ++ /* 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; ++ } ++ } + -+ 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>; -+ }; ++ /* Additional input */ ++ for (i = 0; i < 12; i++) ++ addin[i] = 0; + -+ 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>; -+ }; ++ if (req_sec_strength == 128) ++ addin_length = 64; ++ else if (req_sec_strength == 256) ++ addin_length = 96; ++ else ++ SYNHW_PRINT("Invalid security strength\n"); + -+ 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>; -+ }; ++ if (addin_exists) { ++ opts_str[1] = 0; ++ memcpy(opts_str, buf + 3, 1); + -+ 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>; -+ }; ++ 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"); ++ } + -+ 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>; -+ }; ++ ret = nisttrng_generate(&priv->nisttrng, (u32 *)out, ++ num_gen_bytes, req_sec_strength, ++ pred_resist, addin); ++ if (ret) ++ return -1; + -+ 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>; -+ }; ++ } else { ++ ret = nisttrng_generate(&priv->nisttrng, (u32 *)out, ++ num_gen_bytes, req_sec_strength, ++ pred_resist, NULL); ++ if (ret) ++ return -1; ++ } + -+ 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>; -+ }; ++ /* store the result */ ++ memcpy(priv->rand_out, out, sizeof(out)); + -+ 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>; -+ }; ++ return count; ++} + -+ 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 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; + -+&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>; -+ }; -+}; ++ opts_str[1] = 0; ++ memcpy(opts_str, buf, 1); ++ ret = kstrtouint(opts_str, 16, &opts_int); ++ if (ret) ++ return ret; + -+&edac { -+ status = "okay"; -+}; ++ 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); + -+&mctp0 { -+ status = "okay"; -+ memory-region = <&mctp0_reserved>; -+}; ++ ret = nisttrng_generate_public_vtrng(&priv->nisttrng, ++ (u32 *)out, ++ num_gen_bytes, opts_int); ++ if (ret) ++ return -1; + -+&mctp1 { -+ status = "okay"; -+ memory-region = <&mctp1_reserved>; -+}; ++ memcpy(priv->rand_out, out, sizeof(out)); + -+&mctp2 { -+ status = "okay"; -+ memory-region = <&mctp2_reserved>; -+}; ++ return count; ++} + -+&sgpiom0 { -+ status = "okay"; -+}; ++/* 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; + -+&sgpiom1 { -+ status = "okay"; -+}; ++ /* 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; ++ } ++ } + -+&jtag1 { -+ 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++; ++ } ++ } + -+&adc0 { -+ aspeed,int-vref-microvolt = <2500000>; -+ status = "okay"; ++ strcat(buf, "\n"); ++ return strlen(buf); ++} + -+ 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>; -+}; ++/* 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; + -+&adc1 { -+ aspeed,int-vref-microvolt = <2500000>; -+ status = "okay"; ++ /* If all bits of the rand_reg register are 0, display 0 */ + -+ 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>; -+}; ++ 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]); ++ } ++ } + -+&pinctrl0 { -+ pinctrl_emmcclk_driving: emmcclk-driving { -+ pins = "AC14"; -+ drive-strength = <2>; -+ }; ++ 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++; ++ } + -+ pinctrl_emmccmd_driving: emmccmd-driving { -+ pins = "AE15"; -+ drive-strength = <1>; -+ }; -+ pinctrl_emmc4bit_driving: emmcdat-driving { -+ pins = "AD14", "AE14", "AF14", "AB13"; -+ drive-strength = <1>; -+ }; ++ strcat(buf, "\n"); ++ return strlen(buf); ++} + -+ pinctrl_emmc8bit_driving: emmcdat-driving { -+ pins = "AD14", "AE14", "AF14", "AB13", "AF13", "AC13", "AD13", "AE13"; -+ drive-strength = <1>; -+ }; -+}; ++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; + -+&pinctrl1 { -+ pinctrl_i3c0_3_hv_voltage: i3chv-voltage { -+ pins = "U25"; -+ power-source = <1800>; -+ }; ++ if (sysfs_streq(buf, "full")) { ++ ret = nisttrng_full_kat(&priv->nisttrng); ++ if (ret) ++ return -1; + -+ pinctrl_i3c0_driving: i3c0-driving { -+ pins = "U25", "U26"; -+ drive-strength = <2>; -+ }; ++ } else if (sysfs_streq(buf, "00")) { ++ ret = nisttrng_kat(&priv->nisttrng, 0, 0); ++ if (ret) ++ return -1; + -+ pinctrl_i3c1_driving: i3c1-driving { -+ pins = "Y26", "AA24"; -+ drive-strength = <2>; -+ }; ++ } else if (sysfs_streq(buf, "01")) { ++ ret = nisttrng_kat(&priv->nisttrng, 0, 1); ++ if (ret) ++ return -1; + -+ pinctrl_i3c2_driving: i3c2-driving { -+ pins = "R25", "AA26"; -+ drive-strength = <2>; -+ }; ++ } else if (sysfs_streq(buf, "10")) { ++ ret = nisttrng_kat(&priv->nisttrng, 1, 0); ++ if (ret) ++ return -1; + -+ pinctrl_i3c3_driving: i3c3-driving { -+ pins = "R26", "Y25"; -+ drive-strength = <2>; -+ }; ++ } else if (sysfs_streq(buf, "11")) { ++ ret = nisttrng_kat(&priv->nisttrng, 1, 1); ++ if (ret) ++ return -1; + -+ pinctrl_i3c12_15_hv_voltage: i3chv-voltage { -+ pins = "W25"; -+ power-source = <1800>; -+ }; ++ } else { ++ ret = nisttrng_full_kat(&priv->nisttrng); ++ if (ret) ++ return -1; ++ } + -+ pinctrl_i3c12_driving: i3c12-driving { -+ pins = "W25", "Y23"; -+ drive-strength = <2>; -+ }; ++ return count; ++} + -+ pinctrl_i3c13_driving: i3c13-driving { -+ pins = "Y24", "W21"; -+ drive-strength = <2>; -+ }; ++static void str_to_384_bit(char *buf, u32 *out) ++{ ++ char foo[9]; ++ int i; ++ int ret; + -+ pinctrl_i3c14_driving: i3c14-driving { -+ pins = "AA23", "AC22"; -+ drive-strength = <2>; -+ }; ++ foo[8] = 0; ++ for (i = 0; i < 12; i++) { ++ memcpy(foo, buf + i * 8, 8); ++ ret = kstrtouint(foo, 16, out + 11 - i); ++ } ++} + -+ pinctrl_i3c15_driving: i3c15-driving { -+ pins = "AB22", "Y21"; -+ drive-strength = <2>; -+ }; ++/* 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; + -+ pinctrl_rgmii0_driving: rgmii0-driving { -+ pins = "C20", "C19", "A8", "R14", "A7", "P14", -+ "D20", "A6", "B6", "N14", "B7", "B8"; -+ drive-strength = <1>; -+ }; ++ 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]; + -+ pinctrl_rgmii1_driving: rgmii1-driving { -+ pins = "D19", "C19", "D15", "B12", "B10", "P13", -+ "C18", "C6", "C7", "D7", "N13", "C8"; -+ drive-strength = <1>; -+ }; -+}; ++ for (i = 0; i < 12; i++) ++ addin[i] = i; + -+&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"; -+}; ++ for (i = 0; i < 12; i++) ++ ps[i] = i + 100; + -+&i3c0 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06010000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ /* SDK doc example - Prediction Resistance not available, no Reseed */ ++ err = nisttrng_uninstantiate(&priv->nisttrng); ++ if (err && err != CRYPTO_NOT_INSTANTIATED) ++ return -1; + -+&i3c1 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ if (nisttrng_instantiate(&priv->nisttrng, 128, 0, ps) < 0) ++ return -1; + -+&i3c2 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06012000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ out = kmalloc(10, GFP_KERNEL); ++ if (nisttrng_generate(&priv->nisttrng, out, 10, 128, 0, addin) < 0) ++ return -1; + -+&i3c3 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ DEBUG("----- Generate 10 bytes\n"); ++ for (i = 0; i < 10; i++) ++ DEBUG("%02x", out[i]); + -+&i3c4 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06014000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ DEBUG("\n"); ++ kfree(out); + -+&i3c5 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ out = kmalloc(512, GFP_KERNEL); ++ if (nisttrng_generate(&priv->nisttrng, out, 512, 128, 0, addin) < 0) ++ return -1; + -+&i3c6 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06016000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ DEBUG("----- Generate 512 bytes\n"); ++ for (i = 0; i < 512; i++) ++ DEBUG("%02x", out[i]); + -+&i3c7 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ DEBUG("\n"); ++ kfree(out); + -+&i3c8 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x06018000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ out = kmalloc(41, GFP_KERNEL); ++ if (nisttrng_generate(&priv->nisttrng, out, 41, 128, 0, addin) < 0) ++ return -1; + -+&i3c9 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ DEBUG("----- Generate 41 bytes\n"); ++ for (i = 0; i < 41; i++) ++ DEBUG("%02x", out[i]); + -+&i3c10 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601A000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ DEBUG("\n"); ++ kfree(out); + -+&i3c11 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ err = nisttrng_uninstantiate(&priv->nisttrng); ++ if (err < 0 && err != CRYPTO_NOT_INSTANTIATED) ++ return -1; + -+&i3c12 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601C000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ /* SDK doc example - DRBG Validation */ ++ err = nisttrng_uninstantiate(&priv->nisttrng); ++ if (err && err != CRYPTO_NOT_INSTANTIATED) ++ return -1; + -+&i3c13 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ if (nisttrng_set_nonce_mode(&priv->nisttrng, 1) < 0) ++ return -1; + -+&i3c14 { -+ initial-role = "target"; -+ pid = <0x000007ec 0x0601E000>; -+ dcr = /bits/ 8 <0xcc>; -+ status = "okay"; -+}; ++ out = kmalloc(64, GFP_KERNEL); ++ str_to_384_bit(buf_seed1, tmp); ++ if (nisttrng_get_entropy_input(&priv->nisttrng, tmp, 0) < 0) ++ return -1; + -+&i3c15 { -+ initial-role = "primary"; -+ status = "okay"; -+}; ++ str_to_384_bit(buf_ps1, tmp); ++ if (nisttrng_instantiate(&priv->nisttrng, 256, 1, tmp) < 0) ++ return -1; + -+&uart12 { -+ status = "okay"; -+}; ++ str_to_384_bit(buf_seed2, tmp); ++ if (nisttrng_get_entropy_input(&priv->nisttrng, tmp, 0) < 0) ++ return -1; + -+#if 0 -+&vuart0 { -+ virtual; -+ port = <0x3f8>; -+ sirq = <4>; -+ sirq-polarity = <0>; -+ status = "okay"; -+}; -+#endif ++ str_to_384_bit(buf_addin1, tmp); ++ if (nisttrng_generate(&priv->nisttrng, out, 64, 256, 1, tmp) < 0) ++ return -1; + -+&fmc { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_fwspi_quad_default>; -+ pinctrl-names = "default"; ++ str_to_384_bit(buf_seed3, tmp); ++ if (nisttrng_get_entropy_input(&priv->nisttrng, tmp, 0) < 0) ++ return -1; + -+ 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" -+ }; ++ str_to_384_bit(buf_addin2, tmp); ++ if (nisttrng_generate(&priv->nisttrng, out, 64, 256, 1, tmp) < 0) ++ return -1; + -+ flash@1 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "fmc0:1"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <4>; -+ spi-rx-bus-width = <4>; -+ }; ++ memcpy(priv->rand_out, out, 64); + -+ flash@2 { -+ status = "disabled"; -+ m25p,fast-read; -+ label = "fmc0:2"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <4>; -+ spi-rx-bus-width = <4>; -+ }; -+}; ++ return count; ++} + -+&spi0 { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_spi0_default &pinctrl_spi0_cs1_default>; -+ pinctrl-names = "default"; ++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); + -+ flash@0 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "spi0:0"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; ++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); + -+ flash@1 { -+ status = "disabled"; -+ m25p,fast-read; -+ label = "spi0:1"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; -+}; ++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); + -+&spi1 { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_spi1_default &pinctrl_spi1_cs1_default>; -+ pinctrl-names = "default"; ++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); + -+ flash@0 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "spi1:0"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; ++static DEVICE_ATTR_RW(max_bits_per_req); ++static DEVICE_ATTR_RW(max_req_per_seed); + -+ flash@1 { -+ status = "disabled"; -+ m25p,fast-read; -+ label = "spi1:1"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; -+}; ++static DEVICE_ATTR_WO(test_attr); + -+#if 1 -+&spi2 { -+ compatible = "aspeed,ast2700-spi-txrx"; -+ pinctrl-0 = <&pinctrl_spi2_default>; -+ pinctrl-names = "default"; -+ status = "okay"; ++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, + -+ 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"; ++ &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, + -+ 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>; -+ }; ++ &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, + -+ 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 ++ &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, + -+&can0 { -+ status = "okay"; -+}; ++ &dev_attr_max_bits_per_req.attr, ++ &dev_attr_max_req_per_seed.attr, + -+&emmc_controller { -+ status = "okay"; -+ mmc-hs200-1_8v; ++ &dev_attr_test_attr.attr, NULL }, +}; + -+&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 ++static int nisttrng_self_test(struct nist_trng_state *nist_trng) ++{ ++ u32 seed[16], out[4], x, y; + -+ non-removable; -+ max-frequency = <200000000>; -+}; ++ 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 ++ }; + -+&ufs_controller { -+ status = "okay"; -+}; ++ 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 ++ }; + -+&ufs { -+ status = "okay"; -+ lanes-per-direction = <2>; -+ ref-clk-freq = <26000000>; -+}; ++ int ret, enable, rate, urun; ++ u32 tmp; + -+&chassis { -+ status = "okay"; -+}; ++ for (x = 0; x < 16; x++) ++ seed[x] = 0x12345679 * (x + 1); + -+&mdio0 { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; ++ DEBUG("Doing a self-test with security strength of 128\n"); ++ ret = nisttrng_uninstantiate(nist_trng); ++ if (ret && ret != CRYPTO_NOT_INSTANTIATED) ++ goto ERR; + -+ ethphy0: ethernet-phy@0 { -+ compatible = "ethernet-phy-ieee802.3-c22"; -+ reg = <0>; -+ }; -+}; ++ //if ((ret = nisttrng_set_secure_mode(nist_trng, 0))) { goto ERR; } ++ ret = nisttrng_set_nonce_mode(nist_trng, 1); ++ if (ret) ++ goto ERR; + -+&mdio1 { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; ++ ret = nisttrng_set_sec_strength(nist_trng, 128); ++ if (ret) ++ goto ERR; + -+ 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"; ++ ret = nisttrng_get_entropy_input(nist_trng, seed, 0); ++ if (ret) ++ goto ERR; + -+ phy-mode = "rgmii-id"; -+ phy-handle = <ðphy0>; ++ ret = nisttrng_instantiate(nist_trng, 128, 0, NULL); ++ if (ret) ++ goto ERR; + -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_rgmii0_default &pinctrl_rgmii0_driving>; -+}; ++ if (nist_trng->config.build_cfg0.edu_present) { ++ ret = nisttrng_wait_fifo_full(nist_trng); ++ if (ret) ++ goto ERR; ++ } + -+&mac1 { -+ status = "okay"; ++ ret = nisttrng_generate(nist_trng, out, 16, 128, 0, NULL); ++ if (ret) ++ goto ERR; + -+ phy-mode = "rgmii-id"; -+ phy-handle = <ðphy1>; ++ 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]); + -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_rgmii1_default &pinctrl_rgmii1_driving>; -+}; ++ 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 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>; ++ if (ret) { ++ SYNHW_PRINT("... FAILED comparison\n"); ++ ret = -1; ++ goto ERR; ++ } else { ++ DEBUG("... PASSED\n"); ++ } ++ } + -+ ethphy2: ethernet-phy@0 { -+ compatible = "ethernet-phy-ieee802.3-c22"; -+ reg = <0>; -+ }; -+}; ++ // 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; + -+&sgmii { -+ status = "okay"; -+}; ++ 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; + -+&mac2 { -+ status = "okay"; ++ tmp = pdu_io_read32(nist_trng->base + ++ NIST_TRNG_EDU_STAT); + -+ phy-mode = "sgmii"; -+ phy-handle = <ðphy2>; -+}; -+#endif -+#endif ++ } while (!NIST_TRNG_EDU_STAT_FIFO_EMPTY(tmp)); ++ } + -+&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 -+}; ++ 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; + -+&rtc_over_espi0 { -+ status = "okay"; -+}; ++ ret = nisttrng_set_nonce_mode(nist_trng, 1); ++ if (ret) ++ goto ERR; + -+/* Enable UART2 and UART9 for obmc-console. */ -+&uart2 { -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; ++ ret = nisttrng_set_sec_strength(nist_trng, 256); ++ if (ret) ++ goto ERR; + -+&uart9 { -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; ++ ret = nisttrng_get_entropy_input(nist_trng, seed, 0); ++ if (ret) ++ goto ERR; + -+#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 -+}; ++ ret = nisttrng_instantiate(nist_trng, 256, 0, NULL); ++ if (ret) ++ goto ERR; + -+&rtc_over_espi1 { -+ status = "okay"; -+}; ++ ret = nisttrng_generate(nist_trng, out, 16, 256, 0, NULL); ++ if (ret) ++ goto ERR; + -+/* Enable UART7 and UART10 for obmc-console. */ -+&uart7 { -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ 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]); + -+&uart10 { -+ /delete-property/ pinctrl-names; -+ /delete-property/ pinctrl-0; -+ status = "okay"; -+}; -+#endif /* DUAL_NODE */ ++ 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"); ++ } ++ } ++ } + -+&lpc0_kcs0 { -+ status = "okay"; -+ kcs-io-addr = <0xca0>; -+ kcs-channel = <0>; -+}; ++ // 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; + -+&lpc0_kcs1 { -+ status = "okay"; -+ kcs-io-addr = <0xca8>; -+ kcs-channel = <1>; -+}; ++ 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"); ++ } ++ } + -+&lpc0_kcs2 { -+ status = "okay"; -+ kcs-io-addr = <0xca2>; -+ kcs-channel = <2>; -+}; ++ //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; + -+&lpc0_kcs3 { -+ status = "okay"; -+ kcs-io-addr = <0xca4>; -+ kcs-channel = <3>; -+}; ++ tmp = pdu_io_read32(nist_trng->base + ++ NIST_TRNG_EDU_RBC_CTRL); + -+&lpc0_ibt { -+ status = "okay"; -+}; ++ 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"); ++ } + -+&lpc0_mbox { -+ status = "okay"; -+}; ++ //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); ++ } + -+#if 1 -+&lpc0_snoop { -+ status = "okay"; -+ snoop-ports = <0x80>, <0x81>; -+}; -+#else -+&lpc0_pcc { -+ status = "okay"; -+ pcc-ports = <0x80>; -+}; -+#endif ++ /* back to the noise mode */ ++ ret = nisttrng_set_nonce_mode(nist_trng, 0); ++ if (ret) ++ goto ERR; + -+&lpc0_uart_routing { -+ status = "okay"; -+}; ++ ret = nisttrng_zeroize(nist_trng); ++ if (ret) ++ goto ERR; ++ERR: ++ return ret; ++} + -+&lpc1_kcs0 { -+ status = "okay"; -+ kcs-io-addr = <0xca0>; -+ kcs-channel = <4>; -+}; ++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; + -+&lpc1_kcs1 { -+ status = "okay"; -+ kcs-io-addr = <0xca8>; -+ kcs-channel = <5>; -+}; ++ // version ++ SYNHW_PRINT("DWC_TRNG_DriverSDK_%s\n", TRNG_VERSION); + -+&lpc1_kcs2 { -+ status = "okay"; -+ kcs-io-addr = <0xca2>; -+ kcs-channel = <6>; -+}; ++ cfg = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + -+&lpc1_kcs3 { -+ status = "okay"; -+ kcs-io-addr = <0xca4>; -+ kcs-channel = <7>; -+}; ++ if (!cfg || !irq) { ++ SYNHW_PRINT("no memory or IRQ resource\n"); ++ return -ENOMEM; ++ } + -+&lpc1_ibt { -+ status = "okay"; -+}; ++ 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)); + -+&lpc1_mbox { -+ status = "okay"; -+}; ++ data = devm_kzalloc(&pdev->dev, sizeof(struct synopsys_nisttrng_driver), ++ GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; + -+#if 1 -+&lpc1_snoop { -+ status = "okay"; -+ snoop-ports = <0x80>, <0x81>; -+}; -+#else -+&lpc1_pcc { -+ status = "okay"; -+ pcc-ports = <0x80>; -+}; -+#endif ++ platform_set_drvdata(pdev, data); + -+&lpc1_uart_routing { -+ status = "okay"; -+}; ++ 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); ++ } + -+&video0 { -+ status = "okay"; -+ memory-region = <&video_engine_memory0>; -+}; ++ 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; ++ } + -+&video1 { -+ status = "okay"; -+ memory-region = <&video_engine_memory1>; -+}; ++ /* 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; ++ } ++ } + -+&disp_intf { -+ status = "okay"; -+}; ++ // issue quick self test ++ ret = nisttrng_self_test(&data->nisttrng); ++ if (ret) { ++ devm_kfree(&pdev->dev, data); ++ return -ENOMEM; ++ } + -+&rtc { -+ status = "okay"; -+}; ++ // 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; ++ } + -+&rsss { -+ status = "okay"; -+}; ++ // 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; ++ } + -+&ecdsa { -+ status = "okay"; -+}; ++ 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; ++ } + -+&hace { -+ status = "okay"; -+}; ++ 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)); + -+#if PCIE0_EP -+&bmc_dev0 { -+ status = "okay"; -+ memory-region = <&bmc_dev0_memory>; -+}; ++ 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; + -+&xdma0 { -+ status = "okay"; -+ memory-region = <&xdma_memory0>; -+}; ++ data->hwrng_drv = hwrng_driver_info; ++ ret = hwrng_register(hwrng_driver_info); + -+&pcie_vuart0 { -+ port = <0x3f8>; -+ sirq = <4>; -+ sirq-polarity = <0>; -+ -+ status = "okay"; -+}; ++ 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; ++ } + -+&pcie_vuart1 { -+ port = <0x2f8>; -+ sirq = <3>; -+ sirq-polarity = <0>; ++ 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; ++} + -+ status = "okay"; -+}; ++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; + -+&pcie_lpc0_kcs0 { -+ status = "okay"; -+ kcs-io-addr = <0x3a0>; -+ kcs-channel = <8>; -+}; ++ 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); ++} + -+&pcie_lpc0_kcs1 { -+ status = "okay"; -+ kcs-io-addr = <0x3a8>; -+ kcs-channel = <9>; ++static struct platform_driver s_nisttrng_platform_driver_info = { ++ .probe = nisttrng_driver_probe, ++ .remove = nisttrng_driver_remove, ++ .driver = { ++ .name = "nist_trng", ++ .owner = THIS_MODULE, ++ }, +}; + -+&pcie_lpc0_kcs2 { -+ status = "okay"; -+ kcs-io-addr = <0x3a2>; -+ kcs-channel = <10>; -+}; ++static int __init nisttrng_platform_driver_start(void) ++{ ++ return platform_driver_register(&s_nisttrng_platform_driver_info); ++} + -+&pcie_lpc0_kcs3 { -+ status = "okay"; -+ kcs-io-addr = <0x3a4>; -+ kcs-channel = <11>; -+}; ++static void __exit nisttrng_platform_driver_end(void) ++{ ++ platform_driver_unregister(&s_nisttrng_platform_driver_info); ++} + -+&pcie_lpc0_ibt { -+ status = "okay"; -+ bt-channel = <2>; -+}; ++module_init(nisttrng_platform_driver_start); ++module_exit(nisttrng_platform_driver_end); + -+&pcie0_mmbi0 { -+ status = "okay"; -+ memory-region = <&pcie0_mmbi0_memory>; ++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. ++ */ + -+ bmc-int-value = /bits/ 8 <0x00>; -+ bmc-int-location = <0>; -+}; -+#else /* !PCIE0_EP */ -+&pcie0 { -+ status = "okay"; -+}; -+#endif /* PCIE0_EP */ ++#include "nisttrng_hw.h" ++#include "nisttrng.h" + -+#if PCIE1_EP -+&bmc_dev1 { -+ status = "okay"; -+ memory-region = <&bmc_dev1_memory>; -+}; ++/* Initialize the NIST_TRNG state structure */ ++int nisttrng_init(struct nist_trng_state *state, u32 *base) ++{ ++ int err; ++ u32 tmp; + -+&xdma1 { -+ status = "okay"; -+ memory-region = <&xdma_memory1>; -+}; ++ DEBUG(">> %s: initialize the NIST_TRNG\n", __func__); + -+&pcie_vuart2 { -+ port = <0x3f8>; -+ sirq = <4>; -+ sirq-polarity = <0>; ++ memset(state, 0, sizeof(*state)); + -+ status = "okay"; -+}; ++ state->base = base; + -+&pcie_vuart3 { -+ port = <0x2f8>; -+ sirq = <3>; -+ sirq-polarity = <0>; ++ /* make sure there is no alarm and the core is not busy */ ++ err = nisttrng_get_alarms(state); ++ if (err) ++ goto ERR; + -+ status = "okay"; -+}; ++ err = nisttrng_wait_on_busy(state); ++ if (err) ++ goto ERR; + -+&pcie_lpc1_kcs0 { -+ status = "okay"; -+ kcs-io-addr = <0x3a0>; -+ kcs-channel = <12>; -+}; ++ /* hardware features*/ ++ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_FEATURES); + -+&pcie_lpc1_kcs1 { -+ status = "okay"; -+ kcs-io-addr = <0x3a8>; -+ kcs-channel = <13>; -+}; ++ 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); + -+&pcie_lpc1_kcs2 { -+ status = "okay"; -+ kcs-io-addr = <0x3a2>; -+ kcs-channel = <14>; -+}; ++ /* 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); + -+&pcie_lpc1_kcs3 { -+ status = "okay"; -+ kcs-io-addr = <0x3a4>; -+ kcs-channel = <15>; -+}; ++ /* clear registers */ ++ pdu_io_write32(state->base + NIST_TRNG_REG_ALARM, 0xFFFFFFFF); ++ pdu_io_write32(state->base + NIST_TRNG_REG_ISTAT, 0xFFFFFFFF); + -+&pcie_lpc1_ibt { -+ status = "okay"; -+ bt-channel = <3>; -+}; ++ /* 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; + -+&pcie1_mmbi4 { -+ status = "okay"; -+ memory-region = <&pcie1_mmbi4_memory>; ++ } 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; + -+ bmc-int-value = /bits/ 8 <0x00>; -+ bmc-int-location = <0>; -+}; -+#else /* !PCIE1_EP */ -+&pcie1 { -+ status = "okay"; -+}; -+#endif /* PCIE1_EP */ ++ } else { ++ SYNHW_PRINT("Invalid DRBG architecture"); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } + -+&sdio_controller { -+ status = "okay"; -+ mmc-hs200-1_8v; ++ 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; + -+ 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; -+ }; ++ /* 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); + -+ 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>; -+ }; -+}; ++ /* 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; ++ } + -+&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 */ -+}; ++ DEBUG("initialization is done, going for a zeroize\n"); + -+#if 1 -+&i2c0 { -+ status = "okay"; -+}; ++ // 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); + -+&i2c1 { -+ status = "okay"; -+}; ++ 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); + -+&i2c2 { -+ status = "okay"; -+}; ++ 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); + -+&i2c3 { -+ status = "okay"; -+}; ++ 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); + -+&i2c4 { -+ status = "okay"; -+}; ++ err = nisttrng_zeroize(state); ++ if (err) ++ goto ERR; + -+&i2c5 { -+ status = "okay"; -+}; ++ 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); + -+&i2c6 { -+ status = "okay"; -+}; ++/* 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; + -+&i2c7 { -+ status = "okay"; -+}; ++ DEBUG(">> %s: security strength = %u, pred_resist = %u, personilization string existence = %u\n", ++ __func__, req_sec_strength, pred_resist, (personal_str) ? 1 : 0); + -+&i2c8 { -+ status = "okay"; -+}; ++ /* make sure there is no alarm and the core is not busy */ ++ err = nisttrng_get_alarms(state); ++ if (err) ++ goto ERR; + -+&i2c11 { -+ status = "okay"; -+}; ++ err = nisttrng_wait_on_busy(state); ++ if (err) ++ goto ERR; + -+&i2c12 { -+ status = "okay"; -+}; ++ /* 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; ++ } + -+&i2c13 { -+ status = "okay"; -+}; -+#endif ++ /* 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; ++ } + -+#if 0 -+&ehci0 { -+ status = "okay"; -+}; ++ /* Validate and set the security strength */ ++ err = nisttrng_set_sec_strength(state, req_sec_strength); ++ if (err) ++ goto ERR; + -+&ehci1 { -+ status = "okay"; -+}; -+ -+&uhci0 { -+ status = "okay"; -+ memory-region = <&uhci0_reserved>; -+}; ++ /* 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; ++ } + -+#endif ++ /* 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]; + -+#if 1 -+&uphy3a { -+ status = "okay"; -+}; ++ err = nisttrng_load_ps_addin(state, personal_str); ++ if (err) ++ goto ERR; ++ } + -+&uphy3b { -+ status = "okay"; -+}; -+#endif ++ /* initiate the Create_State command and wait on done */ ++ DEBUG("Create the DRBG state\n"); + -+#if 0 -+&xhci0 { -+ status = "okay"; -+}; ++ 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; + -+&xhci1 { -+ status = "okay"; -+}; -+#endif ++ /* 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; ++ } + -+&vhuba0 { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_usb2ahpd0_default>; -+}; ++ /* reset reminder and alarms counters */ ++ nisttrng_reset_counters(state); + -+&usb3ahp { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_usb3axhp_default &pinctrl_usb2axhp_default>; -+}; ++ //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; + -+&usb3bhp { -+ status = "okay"; -+}; ++ //enable RNC ++ nisttrng_rnc(state, NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_ENABLE); ++ // disable all RBC,s + -+&uphy2b { -+ status = "okay"; -+}; ++ 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); + -+&vhubb1 { -+ status = "okay"; -+}; ++ } else { ++ /* set the prediction resistance */ ++ err = nisttrng_set_pred_resist(state, pred_resist); ++ if (err) ++ goto ERR; ++ } + -+&vhubc { -+ status = "okay"; -+#if 0 -+ pinctrl-0 = <&pinctrl_usb2cud_default>; -+ aspeed,uart-ports = <12>; -+#endif -+}; ++ 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); + -+&ehci3 { -+ status = "okay"; -+}; ++/* Uninstantiate the DRBG state and zeroize */ ++int nisttrng_uninstantiate(struct nist_trng_state *state) ++{ ++ int err; ++ int err_tmp; ++ u32 tmp; + -+&uhci1 { -+ status = "okay"; -+ memory-region = <&uhci1_reserved>; -+}; ++ 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; + -+&wdt0 { -+ 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); ++ } ++ } + -+&wdt1 { -+ 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; + -+&otp { -+ status = "okay"; -+}; ++ /* zeroize */ ++ err = nisttrng_zeroize(state); ++ if (err) ++ goto ERR; + -+#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 (err == CRYPTO_OK && err_tmp == CRYPTO_NOT_INSTANTIATED) ++ err = CRYPTO_NOT_INSTANTIATED; + -+#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-04-08 18:03:31.588010588 +0000 -@@ -0,0 +1,48 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later ++ 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); + -+/dts-v1/; ++/* 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; + -+#include "ast2700a1-evb.dts" ++ tmp_rbc = pdu_io_read32(state->base + NIST_TRNG_EDU_RBC_CTRL); + -+/ { -+ model = "AST2700A1-NCSI"; -+}; ++ 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; ++ } + -+&sgpios { -+ status = "disabled"; -+}; ++ 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); + -+&mac0 { -+ 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); + -+ phy-mode = "rmii"; -+ use-ncsi; ++ 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; ++ } + -+ 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>; -+}; ++ pdu_io_write32(state->base + NIST_TRNG_EDU_RBC_CTRL, tmp_rbc); + -+&mac1 { -+ status = "okay"; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} + -+ phy-mode = "rmii"; -+ use-ncsi; ++/* Reseed */ ++int nisttrng_reseed(struct nist_trng_state *state, int pred_resist, void *addin_str) ++{ ++ int rnc_flag = 0; ++ int 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>; -+}; ++ DEBUG(">> %s: pred_resist = %u, additional strign existence = %u\n", ++ __func__, pred_resist, (addin_str) ? 1 : 0); + -+&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-04-08 18:03:31.588010588 +0000 -@@ -0,0 +1,220 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later ++ 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; + -+/dts-v1/; ++ rnc_flag = 1; ++ } ++ } + -+#include "ast2700a1-evb.dts" ++ /* make sure there is no alarm and the core is not busy */ ++ err = nisttrng_get_alarms(state); ++ if (err) ++ goto ERR; + -+&fmc { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_fwspi_quad_default>; -+ pinctrl-names = "default"; ++ err = nisttrng_wait_on_busy(state); ++ if (err) ++ 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" -+ }; ++ /* 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@1 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "fmc0:1"; -+ 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@2 { -+ status = "disabled"; -+ m25p,fast-read; -+ label = "fmc0:2"; -+ 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; ++ } + -+&spi0 { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_spi0_default &pinctrl_spi0_cs1_default>; -+ pinctrl-names = "default"; ++ /* 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; + -+ flash@0 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "spi0:0"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; ++ /* load the additional input */ ++ err = nisttrng_load_ps_addin(state, addin_str); ++ 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>; -+ }; -+}; ++ } else { ++ /* set the ADDIN_PRESENT field of the MODE register to 0 */ ++ err = nisttrng_set_addin_present(state, 0); ++ if (err) ++ goto ERR; ++ } + -+&spi1 { -+ status = "okay"; -+ pinctrl-0 = <&pinctrl_spi1_default &pinctrl_spi1_cs1_default>; -+ pinctrl-names = "default"; ++ /* 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; + -+ flash@0 { -+ status = "okay"; -+ m25p,fast-read; -+ label = "spi1:0"; -+ spi-max-frequency = <50000000>; -+ spi-tx-bus-width = <2>; -+ spi-rx-bus-width = <2>; -+ }; ++ /* reset reminder and alarms counters */ ++ nisttrng_reset_counters(state); + -+ 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 (rnc_flag) { ++ // rnc_enable ++ err = nisttrng_rnc(state, NIST_TRNG_EDU_RNC_CTRL_CMD_RNC_ENABLE); ++ if (err) ++ goto ERR; ++ } + -+&spi2 { -+ status = "disabled"; -+}; ++ 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); + -+&emmc_controller { -+ status = "disabled"; -+}; ++static int nisttrng_vtrng_wait_on_busy(struct nist_trng_state *state, int priv, int vtrng) ++{ ++ u32 tmp, t; + -+&emmc { -+ status = "disabled"; -+}; ++ t = NIST_TRNG_RETRY_MAX; + -+&ufs_controller { -+ status = "disabled"; -+}; ++ if (priv) { //private vtrng ++ do { ++ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_VSTAT); ++ } while (NIST_TRNG_REG_EDU_VSTAT_BUSY(tmp) && --t); + -+&ufs { -+ status = "disabled"; -+}; ++ } 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); ++ } + -+&video0 { -+ status = "disabled"; -+}; ++ if (t) ++ return CRYPTO_OK; + -+&video1 { -+ status = "disabled"; -+}; ++ SYNHW_PRINT("wait_on_: failed timeout: %08lx\n", ++ (unsigned long)tmp); + -+&disp_intf { -+ status = "disabled"; -+}; ++ return CRYPTO_TIMEOUT; ++} /* nisttrng_vtrng_wait_on_busy */ + -+#if PCIE0_EP -+&bmc_dev0 { -+ status = "disabled"; -+}; ++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; + -+&xdma0 { -+ status = "disabled"; -+}; ++ DEBUG(">> %s : requested number of bytes = %lu, vtrng num = %u\n", ++ __func__, req_num_bytes, vtrng); + -+&pcie_vuart0 { -+ status = "disabled"; -+}; ++ /* make sure random_bits is not NULL */ ++ if (!random_bits) { ++ DEBUG("random_bits pointer cannot be NULL\n"); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } + -+&pcie_vuart1 { -+ status = "disabled"; -+}; ++ if (vtrng > state->config.edu_build_cfg0.public_vtrng_channels) { ++ DEBUG("vtrng channel invalid (%u)\n", vtrng); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } + -+&pcie_lpc0_kcs0 { -+ status = "disabled"; -+}; ++ if (state->status.edu_vstat.rnc_enabled == 0) { ++ DEBUG("rnc_disabled\n"); ++ } + -+&pcie_lpc0_kcs1 { -+ status = "disabled"; -+}; ++ if (state->status.edu_vstat.seed_enum == 0) { ++ DEBUG("not seed_enum\n"); ++ } + -+&pcie_lpc0_kcs2 { -+ status = "disabled"; -+}; ++ /* 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); + -+&pcie_lpc0_kcs3 { -+ status = "disabled"; -+}; ++ 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); + -+&pcie_lpc0_ibt { -+ status = "disabled"; -+}; ++ // check busy ++ err = nisttrng_vtrng_wait_on_busy(state, 0, vtrng); ++ if (err) ++ goto ERR; + -+&pcie0_mmbi0 { -+ status = "disabled"; -+}; -+#else -+&pcie0 { -+ status = "disabled"; -+}; -+#endif ++ // 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); ++ } + -+#if PCIE1_EP -+&bmc_dev1 { -+ status = "disabled"; -+}; ++ // 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); ++ } + -+&xdma1 { -+ status = "disabled"; -+}; ++ /* 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); + -+&pcie_vuart2 { -+ status = "disabled"; -+}; ++ /* 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); + -+&pcie_vuart3 { -+ status = "disabled"; -+}; ++ /* 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; ++ } ++ } ++ } + -+&pcie_lpc1_kcs0 { -+ status = "disabled"; -+}; ++ err = CRYPTO_OK; ++ state->status.current_state = NIST_TRNG_STATE_GENERATE; ++ERR: ++ if (err) ++ random_bits = NULL; + -+&pcie_lpc1_kcs1 { -+ status = "disabled"; -+}; ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} + -+&pcie_lpc1_kcs2 { -+ status = "disabled"; -+}; ++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; + -+&pcie_lpc1_kcs3 { -+ status = "disabled"; -+}; ++ DEBUG(">> %s : requested number of bytes = %lu ", ++ __func__, req_num_bytes); + -+&pcie_lpc1_ibt { -+ status = "disabled"; -+}; ++ /* 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; ++ } + -+&pcie1_mmbi4 { -+ status = "disabled"; -+}; -+#else -+&pcie1 { -+ status = "disabled"; -+}; -+#endif ++ /* make sure random_bits is not NULL */ ++ if (!random_bits) { ++ SYNHW_PRINT("random_bits pointer cannot be NULL\n"); ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } + -+&sdio_controller { -+ status = "disabled"; -+}; ++ if (state->status.edu_vstat.rnc_enabled == 0) { ++ DEBUG("rnc_disabled\n"); ++ } + -+&sdhci { -+ status = "disabled"; -+}; ++ if (state->status.edu_vstat.seed_enum == 0) { ++ DEBUG("not seed_enum\n"); ++ } + -diff --git a/crypto/Makefile b/crypto/Makefile ---- a/crypto/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/crypto/Makefile 2026-04-08 18:03:36.190926635 +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/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-04-08 18:03:48.306705393 +0000 -@@ -0,0 +1,264 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright 2025 Aspeed Technology Inc. -+ */ ++ /* 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); + -+#define ASPEED_CRYPT_NAME "aspeed-crypt" -+#define pr_fmt(fmt) ASPEED_CRYPT_NAME ": " fmt ++ 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); + -+#include -+#include -+#include -+#include -+#include ++ // check busy ++ err = nisttrng_vtrng_wait_on_busy(state, 1, 0); ++ if (err) ++ goto ERR; + -+#include "internal.h" ++ // 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); ++ } + -+enum aspeed_crypt_type { -+ ASPEED_SKCIPHER_TYPE, -+ ASPEED_AHASH_TYPE, -+ ASPEED_AKCIPHER_TYPE, -+ ASPEED_SIG_TYPE, -+}; ++ //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); ++ } + -+struct aspeed_crypt_drv { -+ char *algo; -+ char *drv_name; -+}; ++ /* 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); + -+struct aspeed_crypt_test { -+ char *test_item; -+ enum aspeed_crypt_type type; -+ int num; -+ struct aspeed_crypt_drv *algo; -+}; ++ /* 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); + -+struct aspeed_crypt_drv aspeed_des_binding[] = { -+ { "ecb(des)", "aspeed-ecb-des" }, -+ { "cbc(des)", "aspeed-cbc-des" }, -+ { "ctr(des)", "aspeed-ctr-des" }, -+}; ++ /* 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; ++} + -+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" }, -+}; ++/* 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; + -+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" }, -+}; ++ 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); + -+struct aspeed_crypt_drv aspeed_rsa_binding[] = { -+ { "rsa", "aspeed-rsa" }, -+}; ++ /* make sure there is no alarm and the core is not busy */ ++ err = nisttrng_get_alarms(state); ++ if (err) ++ goto ERR; + -+struct aspeed_crypt_drv aspeed_ecdsa_binding[] = { -+ { "ecdsa-nist-p256", "aspeed-ecdsa-nist-p256" }, -+ { "ecdsa-nist-p384", "aspeed-ecdsa-nist-p384" }, -+}; ++ err = nisttrng_wait_on_busy(state); ++ if (err) ++ goto ERR; + -+static bool aspeed_detect_skcipher_drv(char *drv_name) -+{ -+ struct crypto_skcipher *tfm = NULL; -+ bool found = false; ++ /* 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; ++ } + -+ tfm = crypto_alloc_skcipher(drv_name, 0, 0); -+ if (!IS_ERR(tfm)) { -+ found = true; -+ crypto_free_skcipher(tfm); ++ /* 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; + } + -+ return found; -+} ++ /* 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; + -+static bool aspeed_detect_ahash_drv(char *drv_name) -+{ -+ struct crypto_ahash *tfm = NULL; -+ bool found = false; ++ /* 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; + -+ tfm = crypto_alloc_ahash(drv_name, 0, 0); -+ if (!IS_ERR(tfm)) { -+ found = true; -+ crypto_free_ahash(tfm); ++ /* make sure random_bits is not NULL */ ++ if (!random_bits) { ++ DEBUG("random_bits pointer cannot be NULL\n"); ++ err = CRYPTO_FAILED; ++ goto ERR; + } + -+ return found; -+} -+ -+static bool aspeed_detect_akcipher_drv(char *drv_name) -+{ -+ struct crypto_akcipher *tfm = NULL; -+ bool found = false; ++ /* 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; + -+ tfm = crypto_alloc_akcipher(drv_name, 0, 0); -+ if (!IS_ERR(tfm)) { -+ found = true; -+ crypto_free_akcipher(tfm); ++ 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; + } + -+ return found; -+} ++ do { ++ void *generate_addin_str = addin_str; + -+static bool aspeed_detect_sig_drv(char *drv_name) -+{ -+ struct crypto_sig *tfm = NULL; -+ bool found = false; ++ if (pred_resist | reseed_required) { ++ err = nisttrng_reseed(state, pred_resist, addin_str); ++ if (err) ++ goto ERR; + -+ tfm = crypto_alloc_sig(drv_name, 0, 0); -+ if (!IS_ERR(tfm)) { -+ found = true; -+ crypto_free_sig(tfm); -+ } ++ /* 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; + -+ return found; -+} ++ /* ADDIN_PRESENT field in MODE has to be set back to 0 to avoid illegal cmd sequence */ ++ reseed_required = 0; ++ } + -+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; -+ } -+} ++ /* generate process */ ++ if (nisttrng_check_seed_lifetime(state) == CRYPTO_RESEED_REQUIRED) { ++ reseed_required = 1; + -+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]; -+ } ++ } else { ++ reseed_required = 0; + -+ return NULL; -+} ++ /* 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; ++ } + -+static __maybe_unused int aspeed_crypt_run_tests(char *alg_name) -+{ -+ const struct aspeed_crypt_test *ts; -+ int ret = 0; -+ int i = 0; ++ /* Generate all random bits */ ++ /* if EDU present then get random number from private vtrng */ + -+ ts = aspeed_crypt_get_alg(alg_name); -+ if (!ts) { -+ pr_err("No test suite found for algorithm: %s", alg_name); -+ return -EINVAL; -+ } ++ //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; + -+ 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; ++ } else { ++ err = nisttrng_gen_random(state, random_bits, ++ req_num_bytes); ++ if (err) ++ goto ERR; + -+ pr_info("alg: %s tests %s\n", ts->algo[i].algo, -+ !ret ? "passed" : "failed"); -+ } ++ /* 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); + -+ return ret; -+} ++ err = CRYPTO_OK; ++ state->status.current_state = NIST_TRNG_STATE_GENERATE; ++ERR: ++ if (err) ++ random_bits = NULL; + -+#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) ++ 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. ++ */ ++ ++#include "nisttrng_hw.h" ++#include "nisttrng.h" ++ ++/* Wait functions */ ++static int nisttrng_wait_on_(struct nist_trng_state *state, u32 mask) +{ -+ u8 kbuf[16] = { 0 }; ++ u32 tmp; ++ int t; + -+ if (count > sizeof(kbuf) - 1) -+ return -EINVAL; ++ t = NIST_TRNG_RETRY_MAX; + -+ if (copy_from_user(kbuf, ubuf, min(count, sizeof(kbuf)))) -+ return -EFAULT; -+ strim(kbuf); ++ do { ++ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_ISTAT); ++ } while (!(tmp & (mask | NIST_TRNG_REG_ISTAT_ALARMS)) && --t); + -+ if (!aspeed_crypt_run_tests(kbuf)) -+ pr_err("alg: %s tests passed\n", kbuf); -+ else -+ pr_err("alg: %s tests failed\n", kbuf); ++ if (tmp & NIST_TRNG_REG_ISTAT_ALARMS) ++ return nisttrng_get_alarms(state); + -+ return min(count, sizeof(kbuf)); -+} -+#endif ++ if (t) { ++ pdu_io_write32(state->base + NIST_TRNG_REG_ISTAT, mask); ++ return CRYPTO_OK; + -+static const struct file_operations fops = { -+ .owner = THIS_MODULE, -+ .write = aspeed_crypt_write, -+}; ++ } else { ++ SYNHW_PRINT("wait_on_: failed timeout: %08lx\n", ++ (unsigned long)tmp); ++ return CRYPTO_TIMEOUT; ++ } ++} /* nisttrng_wait_on_ */ + -+static dev_t dev; -+static struct cdev cdev; -+static struct class *class; -+static int __init acrypt_mod_init(void) ++int nisttrng_wait_on_done(struct nist_trng_state *state) +{ -+ int ret; -+ -+ ret = alloc_chrdev_region(&dev, 0, 1, ASPEED_CRYPT_NAME); -+ if (ret < 0) -+ return ret; ++ return nisttrng_wait_on_(state, NIST_TRNG_REG_ISTAT_DONE); ++} /* nisttrng_wait_on_done */ ++EXPORT_SYMBOL(nisttrng_wait_on_done); + -+ cdev_init(&cdev, &fops); -+ ret = cdev_add(&cdev, dev, 1); -+ if (ret) -+ goto del_region; ++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 */ + -+ class = class_create(ASPEED_CRYPT_NAME); -+ if (IS_ERR(class)) { -+ ret = PTR_ERR(class); -+ goto del_cdev; -+ } ++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 */ + -+ 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 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 */ + -+static void __exit acrypt_mod_fini(void) ++int nisttrng_wait_on_busy(struct nist_trng_state *state) +{ -+ device_destroy(class, dev); -+ class_destroy(class); -+ cdev_del(&cdev); -+ unregister_chrdev_region(dev, 1); -+} ++ u32 tmp, t; + -+subsys_initcall(acrypt_mod_init); -+module_exit(acrypt_mod_fini); -diff --git a/drivers/Makefile b/drivers/Makefile ---- a/drivers/Makefile 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/Makefile 2026-04-08 18:03:39.533865664 +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 2026-04-08 18:03:34.258961872 +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 ++ t = NIST_TRNG_RETRY_MAX; + - 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 2026-04-08 18:03:38.952876260 +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 2026-04-08 18:03:48.139708444 +0000 -@@ -0,0 +1,1173 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+// Copyright ASPEED Technology -+ -+#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 }, -+}; ++ do { ++ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_STAT); ++ } while ((tmp & NIST_TRNG_REG_STAT_BUSY) && --t); + -+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; ++ if (t) ++ return CRYPTO_OK; + -+ /* 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; -+}; ++ 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); + -+static int ltpi_get_link_partner(struct aspeed_ltpi_priv *ltpi) ++/* Read and return alarm. Zeroize if there is an alarm*/ ++int nisttrng_get_alarms(struct nist_trng_state *state) +{ -+ u32 reg = readl(ltpi->regs + LTPI_LINK_MNG_ST); -+ -+ return FIELD_GET(REG_LTPI_LINK_PARTNER_FLAG, reg); -+} ++ u32 tmp; + -+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); ++ 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; + -+ 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"); ++ /* 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; + } + -+ writel(status, priv->regs + LTPI_INTR_STATUS); -+ -+ return IRQ_HANDLED; -+} ++ if (state->status.alarm_code) ++ return CRYPTO_FATAL; ++ else ++ return CRYPTO_OK; ++} /* nisttrng_get_alarms */ ++EXPORT_SYMBOL(nisttrng_get_alarms); + -+static int aspeed_ltpi_init_mux(struct aspeed_ltpi_priv *priv) ++/* Reset reminder and alarm counters */ ++int nisttrng_reset_counters(struct nist_trng_state *state) +{ -+ u32 reg, i2c_en, uart_en, i; ++ state->counters.bits_per_req_left = state->counters.max_bits_per_req; ++ state->counters.req_per_seed_left = state->counters.max_req_per_seed; + -+ reg = readl(priv->regs + LTPI_AUTO_CAP_LOW); ++ return 0; ++} /* nisttrng_reset_counters */ ++EXPORT_SYMBOL(nisttrng_reset_counters); + -+ i2c_en = FIELD_GET(LTPI_I2C_IO_FRAME_EN, reg); -+ i2c_en &= priv->i2c_tunneling; ++/* 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; + -+ reg &= ~LTPI_I2C_IO_FRAME_EN; -+ reg |= FIELD_PREP(LTPI_I2C_IO_FRAME_EN, i2c_en); -+ writel(reg, priv->regs + LTPI_MANUAL_CAP_LOW); ++ return 0; ++} /* nisttrng_reset_state */ + -+ reg = readl(priv->regs + LTPI_AUTO_CAP_HIGH); ++/* ---------- Set field APIs ---------- */ + -+ uart_en = FIELD_GET(LTPI_UART_IO_FRAME_EN, reg); -+ uart_en &= priv->uart_tunneling; ++/* ++ * 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; + -+ reg &= ~LTPI_UART_IO_FRAME_EN; -+ reg |= FIELD_PREP(LTPI_UART_IO_FRAME_EN, uart_en); ++ DEBUG(">> %s: security strength = %i\n", __func__, ++ req_sec_strength); + -+ writel(reg, priv->regs + LTPI_MANUAL_CAP_HIGH); ++ /* 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; + -+ /* Apply LTPI manual configuration */ -+ reg = readl(priv->regs + LTPI_LINK_CONTROLL); -+ reg &= ~LTPI_AUTO_CONFIG; -+ writel(reg, priv->regs + LTPI_LINK_CONTROLL); ++ } else if (((req_sec_strength > 128) && ++ (req_sec_strength <= 256)) && ++ (state->config.features.drbg_arch == AES256)) { ++ chosen_sec_strength = SEC_STRNT_AES256; + -+ /* 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)); -+ } ++ } 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); + -+ return 0; -+} -+ -+static int clz16(u16 x) -+{ -+ int n = 0; ++ /* 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; + -+ if (x == 0) -+ return 16; ++ } 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); + -+ if (x <= 0x00ff) { -+ n += 8; -+ x <<= 8; -+ } -+ if (x <= 0x0fff) { -+ n += 4; -+ x <<= 4; -+ } -+ if (x <= 0x3fff) { -+ n += 2; -+ x <<= 2; ++ state->status.pad_ps_addin = 0; ++ state->status.sec_strength = chosen_sec_strength; + } -+ 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); -+} ++ err = CRYPTO_OK; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_set_sec_strength */ ++EXPORT_SYMBOL(nisttrng_set_sec_strength); + -+static int ltpi_phy_set_mode(struct aspeed_ltpi_priv *ltpi, int mode) ++/* ++ * 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 reg; ++ u32 tmp; + -+ if (mode < 0 || mode > LTPI_PHY_MODE_CDR_HI_SP) { -+ dev_err(ltpi->dev, "%s: invalid mode %d\n", __func__, mode); -+ return -1; -+ } ++ DEBUG(">> %s, adding_present = %u\n", __func__, ++ addin_present); + -+ reg = readl(ltpi->phy_regs + LTPI_PHY_CTRL); -+ reg &= ~REG_LTPI_PHY_MODE; -+ reg |= mode; -+ writel(reg, ltpi->phy_regs + LTPI_PHY_CTRL); ++ 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); + -+static int ltpi_phy_set_clksel(struct aspeed_ltpi_priv *ltpi, int clksel, -+ bool is_op_clk) ++/* ++ * 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) +{ -+ 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); ++ int err; ++ u32 tmp; + -+ if (ltpi->clk_inverse & RX_CLK_INVERSE) -+ reg |= REG_LTPI_RX_PHY_CLK_INV; ++ DEBUG(">> %s: pred_resist = %u\n", __func__, pred_resist); + -+ if (ltpi->clk_inverse & TX_CLK_INVERSE) -+ reg |= REG_LTPI_TX_PHY_CLK_INV; ++ /* 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; ++ } + -+ if (is_op_clk) -+ reg |= REG_LTPI_PLL_SET; ++ 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); + -+ writel(reg, ltpi->phy_regs + LTPI_PLL_CTRL); ++ state->status.pred_resist = pred_resist; + -+ return 0; -+} ++ err = CRYPTO_OK; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_set_pred_resist */ ++EXPORT_SYMBOL(nisttrng_set_pred_resist); + -+static void ltpi_set_crc_format(struct aspeed_ltpi_priv *ltpi, int crc_fmt) ++/* ++ * 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) +{ -+ u32 val = readl(ltpi->regs + LTPI_CRC_OPTION); ++ int err; ++ u32 tmp; ++ int t; + -+ 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: secure_mode = %u\n", __func__, secure_mode); + -+ writel(val, ltpi->regs + LTPI_CRC_OPTION); -+} ++ t = NIST_TRNG_RETRY_MAX; + -+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); ++ 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); + -+ reset_control_deassert(ltpi->ltpi_rst); ++ /* 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); + -+ ltpi_phy_unlock(ltpi); ++ if (!t) { ++ err = CRYPTO_TIMEOUT; ++ goto ERR; ++ } + -+ return 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); ++ } + -+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)); -+} ++ 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); + -+static int ltpi_poll_link_mng_state(struct aspeed_ltpi_priv *ltpi, -+ u32 expected, u32 unexpected, -+ int timeout_us) ++/* ++ * 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) +{ -+ u32 state; -+ int ret; ++ int err; ++ u32 tmp; ++ int t; + -+ 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); ++ DEBUG(">> %s: nonce_mode = %u\n", __func__, nonce_mode); + -+ if (FIELD_GET(REG_LTPI_LINK_MNG_ST, state) == unexpected) -+ return -ENOLINK; ++ t = NIST_TRNG_RETRY_MAX; + -+ if (ret) -+ return -ETIMEDOUT; ++ 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); + -+ return 0; -+} ++ /* 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); + -+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); -+} ++ if (!t) { ++ err = CRYPTO_TIMEOUT; ++ goto ERR; ++ } + -+static int ltpi_wait_state_op(struct aspeed_ltpi_priv *ltpi) -+{ -+ u32 val = readl(ltpi->regs + LTPI_LINK_ST); ++ /* 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); ++ } + -+ val |= (REG_LTPI_CON_ACC_TO_ERR | REG_LTPI_FRM_CRC_ERR | -+ REG_LTPI_LINK_LOST_ERR); -+ writel(val, ltpi->regs + LTPI_LINK_ST); ++ state->status.nonce_mode = nonce_mode; + -+ return ltpi_poll_link_mng_state(ltpi, LTPI_LINK_MNG_ST_OP, -+ LTPI_LINK_MNG_ST_DETECT_ALIGN, -+ ltpi->ad_timeout); -+} ++ err = CRYPTO_OK; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_set_nonce_mode */ ++EXPORT_SYMBOL(nisttrng_set_nonce_mode); + -+static int ltpi_set_lvds_io_driving(struct aspeed_ltpi_priv *ltpi, int driving) ++/* ---------- 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) +{ -+ u32 val; ++ int err; ++ int i, j; ++ int str_size; + -+ 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); ++ DEBUG(">> %s starts...\n", __func__); + -+ 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); ++ /* return error if the pointer is NULL */ ++ if (!input_str) { ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } + -+ /* tx1: clk, tx0: data */ -+ if (driving & BIT(1)) -+ val |= (REG_LTPI_LVDS_TX1_DS1 | REG_LTPI_LVDS_TX0_DS1); ++ /* 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 */ + -+ if (driving & BIT(0)) -+ val |= (REG_LTPI_LVDS_TX1_DS0 | REG_LTPI_LVDS_TX0_DS0); ++ for (i = 0; i < str_size; i++) { ++ pdu_io_write32(state->base + NIST_TRNG_REG_NPA_DATA0 + i, ++ ((u32 *)input_str)[i]); ++ } + -+ writel(val, ltpi->top_regs + LTPI_LVDS_TX_CTRL); ++ 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); + -+ return 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); + -+static int ltpi_set_local_speed_cap(struct aspeed_ltpi_priv *ltpi, -+ u32 speed_cap) ++/* ---------- 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) +{ -+ 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); ++ int err; ++ int nonce_ld_cntr = 0; ++ int i, j; + -+ return 0; -+} ++ DEBUG(">> %s: seeding mode = %s, nonce_operation = %u\n", __func__, ++ (state->status.nonce_mode ? "Nonce" : "Noise"), nonce_operation); + -+static void ltpi_do_link_training(struct aspeed_ltpi_priv *ltpi) -+{ -+ u32 val; ++ /* make sure there is no alarm and the core is not busy */ ++ err = nisttrng_get_alarms(state); ++ if (err) ++ goto ERR; + -+ /* Reset the PHY to PHY_MODE_OFF */ -+ ltpi_reset(ltpi); ++ err = nisttrng_wait_on_busy(state); ++ if (err) ++ goto ERR; + -+ 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); ++ /* --- Seeding --- */ ++ if (state->status.nonce_mode) { /* --- nonce mode --- */ ++ if (!input_nonce) { ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } + -+ /* -+ * 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); ++ nonce_ld_cntr = 0; + -+ /* -+ * 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); ++ 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; + -+ /* Set the clock source to the base frequency 25MHz */ -+ ltpi_phy_set_clksel(ltpi, REG_LTPI_PLL_25M, false); ++ 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]); ++ } + -+ /* To make the remote side back to the link lost state */ -+ mdelay(ADVERTISE_TIMEOUT_US / 1000); ++ /* issue the command and wait on done */ ++ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, ++ NIST_TRNG_REG_CTRL_CMD_GEN_NONCE); + -+ ltpi_phy_set_mode(ltpi, LTPI_PHY_MODE_SDR); -+} ++ if (nisttrng_wait_on_done(state)) { ++ err = CRYPTO_FATAL; ++ goto ERR; ++ }; ++ } + -+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; ++ } 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); + -+ 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); ++ if (nisttrng_wait_on_done(state)) { ++ err = CRYPTO_FATAL; ++ goto ERR; ++ }; ++ } + -+ return (25000000 * (m + 1) / (n + 1) / (p + 1)); -+} ++ err = CRYPTO_OK; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_get_entropy_input */ ++EXPORT_SYMBOL(nisttrng_get_entropy_input); + -+static int scu_set_pll_freq(struct aspeed_ltpi_priv *ltpi, int pll_id, int freq) ++/* ++ * 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) +{ -+ const struct pll_info *info; -+ const struct pll_param *param; -+ int curr_freq, i; -+ bool match = false; -+ -+ if (pll_id > 1) -+ return -EINVAL; ++ int err; + -+ curr_freq = scu_get_pll_freq(ltpi, pll_id); -+ if (curr_freq == freq) -+ return 0; ++ DEBUG(">> %s starts...\n", __func__); + -+ for (i = 0; i < NUM_PLL_PARAM; i++) { -+ if (freq == pll_param_lookup[i].freq) { -+ match = true; -+ break; -+ } ++ /* if the DRBG is not intantiated return error */ ++ if (!DRBG_INSTANTIATED(state->status.current_state)) { ++ err = CRYPTO_FAILED; ++ goto ERR; + } + -+ if (!match) -+ return -EINVAL; ++ /* 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; + -+ param = &pll_param_lookup[i]; -+ info = &scu_pll_info[pll_id]; ++ /* This API should not be called with a NULL additional input string */ ++ if (!addin_str) { ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } + -+ 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); ++ /* set the ADDIN_PRESENT field of the MODE register to 1 */ ++ err = nisttrng_set_addin_present(state, 1); ++ if (err) ++ goto ERR; + -+ udelay(5); -+ regmap_update_bits(ltpi->scu, info->reg_offset0, PLL_REG1_RESET, 0); -+ udelay(20); ++ err = nisttrng_load_ps_addin(state, addin_str); ++ if (err) ++ goto ERR; + -+ return 0; -+} ++ /* execute the command and wait on done*/ ++ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, ++ NIST_TRNG_REG_CTRL_CMD_REFRESH_ADDIN); + -+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; ++ err = nisttrng_wait_on_done(state); ++ if (err) ++ goto ERR; + -+ pll_id = ltpi->index; /* 0 or 1 maps to L0PLL or L1PLL in array */ ++ err = 0; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_refresh_addin */ ++EXPORT_SYMBOL(nisttrng_refresh_addin); + -+ /* find max attainable speed */ -+ target_speed = find_max_speed(speed_cap); ++/* ++ * 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; + -+ /* set phy mode "OFF" */ -+ ltpi_phy_set_mode(ltpi, LTPI_PHY_MODE_OFF); ++ DEBUG(">> %s: req_num_bytes = %lu\n", __func__, req_num_bytes); + -+ 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; ++ /* if the DRBG is not intantiated return error */ ++ if (!DRBG_INSTANTIATED(state->status.current_state)) { ++ err = CRYPTO_FAILED; ++ goto ERR; + } -+ 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); ++ /* make sure there is no alarm and the core is not busy */ ++ err = nisttrng_get_alarms(state); ++ if (err) ++ goto ERR; + -+ return target_speed; -+} ++ err = nisttrng_wait_on_busy(state); ++ if (err) ++ goto ERR; + -+static int ltpi_scm_init(struct aspeed_ltpi_priv *ltpi) -+{ -+ int ret, target_speed; -+ u32 reg, state; ++ /* 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; ++ } + -+ 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; ++ /* make sure random_bits is not NULL */ ++ if (!random_bits) { ++ DEBUG("random_bits pointer cannot be NULL\n"); ++ err = CRYPTO_FAILED; ++ goto ERR; + } + -+ ltpi->t_link_detect = ktime_get_ns(); ++ /* 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); + -+ /* 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; ++ 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); + -+ 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; -+ } ++ err = nisttrng_wait_on_done(state); ++ if (err) ++ goto ERR; + -+ 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; -+ } ++ /* 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 (!ltpi->disable_auto_downshift) -+ /* clear the bit to specify the current speed doesn't work */ -+ ltpi->phy_speed_cap &= ~BIT(target_speed); ++ if (state->counters.bits_per_req_left < 0) { ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } + -+ /* 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; ++ } else { ++ memcpy(random_bits + i * (NIST_TRNG_RAND_BLK_SIZE_BITS / 8) + ++ j * 4, &tmp, remained_bytes); + -+ dev_warn(ltpi->dev, -+ "Failed to enter operational state, restarting link training\n"); -+ } while (1); ++ /* 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; + -+ dev_info(ltpi->dev, "LTPI Link trained successfully\n"); -+ return 0; ++ if (state->counters.bits_per_req_left < 0) { ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } ++ break; ++ } ++ } ++ } + -+ltpi_scm_exit: -+ dev_err(ltpi->dev, "Exiting initialization\n"); -+ ltpi_reset(ltpi); -+ return ret; -+} ++ err = CRYPTO_OK; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_gen_random */ ++EXPORT_SYMBOL(nisttrng_gen_random); + -+/* Sysfs attribute show/store functions */ -+static ssize_t ad_timeout_show(struct device *dev, -+ struct device_attribute *attr, char *buf) ++/* ++ * 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) +{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ int err; + -+ return sprintf(buf, "%d\n", priv->ad_timeout); -+} ++ DEBUG(">> %s starts...\n", __func__); + -+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 the DRBG is not intantiated return error */ ++ if (!DRBG_INSTANTIATED(state->status.current_state)) { ++ err = CRYPTO_FAILED; ++ goto ERR; ++ } + -+ if (kstrtouint(buf, 0, &val)) -+ return -EINVAL; ++ /* make sure there is no alarm and the core is not busy */ ++ err = nisttrng_get_alarms(state); ++ if (err) ++ goto ERR; + -+ priv->ad_timeout = val; -+ return count; -+} ++ err = nisttrng_wait_on_busy(state); ++ if (err) ++ goto ERR; + -+static ssize_t io_driving_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ /* 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; + -+ return sprintf(buf, "0x%x\n", priv->io_driving); -+} ++ /* 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 */ + -+static ssize_t io_driving_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, -+ size_t count) ++int nisttrng_check_seed_lifetime(struct nist_trng_state *state) +{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); -+ unsigned int val; ++ int err; + -+ if (kstrtouint(buf, 0, &val)) -+ return -EINVAL; ++ if (state->counters.req_per_seed_left <= 0) { ++ DEBUG("maximum number of requests per seed is reached\n"); ++ err = CRYPTO_RESEED_REQUIRED; ++ goto ERR; ++ } + -+ priv->io_driving = val; -+ return count; ++ err = CRYPTO_OK; ++ERR: ++ return err; +} ++EXPORT_SYMBOL(nisttrng_advance_state); + -+static ssize_t clk_inverse_show(struct device *dev, -+ struct device_attribute *attr, char *buf) ++/* ++ * 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) +{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ int err; ++ u32 tmp; + -+ return sprintf(buf, "0x%x\n", priv->clk_inverse); -+} ++ DEBUG(">> %s: kat_sel = %u, kat_vec = %u\n", __func__, ++ kat_sel, kat_vec); + -+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; ++ /* 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); + -+ if (kstrtouint(buf, 0, &val)) -+ return -EINVAL; ++ /* issue the command and wait on kat_completed */ ++ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, ++ NIST_TRNG_REG_CTRL_CMD_KAT); + -+ priv->clk_inverse = val; -+ return count; -+} ++ err = nisttrng_wait_on_kat_completed(state); ++ if (err) ++ goto ERR; + -+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); ++ /* check for alarms */ ++ err = nisttrng_get_alarms(state); ++ if (err) ++ goto ERR; + -+ return sprintf(buf, "%d\n", priv->link_speed_frm_rx_cnt); -+} ++ err = CRYPTO_OK; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_kat */ ++EXPORT_SYMBOL(nisttrng_kat); + -+static ssize_t link_speed_frm_rx_cnt_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) ++/* ++ * 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) +{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); -+ unsigned int val; -+ -+ if (kstrtouint(buf, 0, &val)) -+ return -EINVAL; ++ int err; + -+ priv->link_speed_frm_rx_cnt = val; -+ return count; -+} ++ DEBUG(">> %s starts...\n", __func__); + -+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); ++ /* SEL = 0, Vec = 0 */ ++ err = nisttrng_kat(state, 0, 0); ++ if (err) ++ goto ERR; + -+ return sprintf(buf, "%d\n", priv->disable_auto_downshift); -+} ++ /* SEL = 0, Vec = 1 */ ++ err = nisttrng_kat(state, 0, 1); ++ if (err) ++ goto ERR; + -+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; ++ /* SEL = 1, Vec = 0 */ ++ err = nisttrng_kat(state, 1, 0); ++ if (err) ++ goto ERR; + -+ if (kstrtouint(buf, 0, &val)) -+ return -EINVAL; ++ /* SEL = 1, Vec = 1 */ ++ err = nisttrng_kat(state, 1, 1); ++ if (err) ++ goto ERR; + -+ priv->disable_auto_downshift = val ? 1 : 0; -+ return count; -+} ++ err = CRYPTO_OK; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} /* nisttrng_full_kat */ ++EXPORT_SYMBOL(nisttrng_full_kat); + -+static ssize_t crc_format_show(struct device *dev, -+ struct device_attribute *attr, char *buf) ++/* ++ * 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) +{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ int err; + -+ return sprintf(buf, "%d\n", priv->crc_format); -+} ++ DEBUG(">> %s: %lu\n", __func__, max_bits_per_req); + -+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 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; ++ } + -+ if (kstrtouint(buf, 0, &val)) -+ return -EINVAL; ++ /* 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; ++ } + -+ priv->crc_format = val ? 1 : 0; -+ return count; ++ 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); + -+static ssize_t phy_speed_cap_show(struct device *dev, -+ struct device_attribute *attr, char *buf) ++/* ++ * 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) +{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ int err; + -+ return sprintf(buf, "0x%x\n", priv->phy_speed_cap); -+} ++ DEBUG(">> %s: %llu\n", __func__, max_req_per_seed); + -+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 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; ++ } + -+ if (kstrtouint(buf, 0, &val)) -+ return -EINVAL; ++ /* 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; ++ } + -+ priv->phy_speed_cap = val; -+ return count; ++ 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); + -+static ssize_t op_timeout_show(struct device *dev, -+ struct device_attribute *attr, char *buf) ++/* ++ * 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) +{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); ++ int err; + -+ return sprintf(buf, "%llu\n", priv->op_timeout); -+} ++ DEBUG(">> %s: zeroize the core\n", __func__); + -+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; ++ /* issue zeroize command */ ++ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, ++ NIST_TRNG_REG_CTRL_CMD_ZEROIZE); + -+ if (kstrtoull(buf, 0, &val)) -+ return -EINVAL; ++ /* wait on zeroize done */ ++ err = nisttrng_wait_on_zeroize(state); ++ if (err) ++ goto ERR; + -+ priv->op_timeout = val; -+ return count; -+} ++ /* reset the SW state */ ++ nisttrng_reset_state(state); + -+static ssize_t rescan_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t count) ++ 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) +{ -+ struct aspeed_ltpi_priv *priv = dev_get_drvdata(dev); -+ u32 val, reg; ++ int err = 0; ++ u32 tmp; + -+ if (kstrtouint(buf, 0, &val)) -+ return -EINVAL; ++ DEBUG(">> %s cmd %d\n", __func__, rnc_ctrl_cmd); + -+ 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); ++ 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; + } + -+ return count; -+} ++ if (!state->config.build_cfg0.edu_present) { ++ DEBUG(">> edu not present\n"); ++ err = -1; ++ goto ERR; ++ } + -+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" }; ++ 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; + -+ 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, -+}; ++ // 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)); + -+static const struct attribute_group aspeed_ltpi_attr_group = { -+ .attrs = aspeed_ltpi_attrs, -+}; ++ state->status.edu_vstat.rnc_enabled = 0; ++ } ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} ++EXPORT_SYMBOL(nisttrng_rnc); + -+static int aspeed_ltpi_probe(struct platform_device *pdev) ++int nisttrng_wait_fifo_full(struct nist_trng_state *state) +{ -+ 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; ++ int err = 0; ++ u32 tmp, t; + -+ match = of_match_device(dev->driver->of_match_table, dev); ++ t = NIST_TRNG_RETRY_MAX; + -+ if (match) { -+ if (of_property_match_string(np, "compatible", -+ match->compatible) < 0) -+ return -ENODEV; -+ } else { -+ return -ENODEV; -+ } ++ DEBUG(">> %s starts...\n", __func__); + -+ 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); ++ do { ++ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_STAT); ++ } while ((!NIST_TRNG_EDU_STAT_FIFO_FULL(tmp)) && --t); + -+ clk_prepare_enable(priv->ltpi_phyclk); ++ if (t) { ++ err = CRYPTO_OK; + } else { -+ priv->ltpi_phyclk = NULL; ++ DEBUG("wait_on_fifo_full: failed timeout: %08lx\n", ++ (unsigned long)tmp); ++ err = CRYPTO_TIMEOUT; ++ goto ERR; + } + -+ 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; ++ERR: ++ DEBUG("--- Return %s, err = %i\n", __func__, err); ++ return err; ++} +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) + -+ 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; ++#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; + -+ /* 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); ++ 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 }, ++}; + -+ regmap_read(priv->scu, SCU_IO_OTP_TRAP1, ®); -+ regmap_write(priv->scu, SCU_IO_OTP_TRAP1_CLEAR, reg); + 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; + -+ 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; ++ /* 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); + } -+ -+ 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); ++ if (mask & KCS_BMC_EVENT_TYPE_IBF) { ++ const bool enable = !!(state & KCS_BMC_EVENT_TYPE_IBF); + -+ /* 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; ++ 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; ++ } + } -+ -+ 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, -+ }, ++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, +}; + -+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-04-08 18:03:48.134708536 +0000 -@@ -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/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 2026-04-08 18:03:35.280943232 +0000 -@@ -587,6 +587,21 @@ + /* +- * 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 unsure, say Y. +- if (WARN_ON(nr_addrs < 1 || nr_addrs > 2)) +- return -EINVAL; ++ io_addr = kcs_aspeed->io_addr; -+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 +- 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; + } - 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 2026-04-08 18:03:40.212853274 +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 2026-04-08 18:03:48.278705905 +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; +-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; + } + +-static void aspeed_kcs_enable_channel(struct kcs_bmc_device *kcs_bmc, bool enable) ++static int aspeed_kcs_enable_channel(struct aspeed_kcs_bmc *kcs_aspeed, bool enable) + { +- struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc); +- +- switch (kcs_bmc->channel) { ++ switch (kcs_aspeed->hw_inst) { ++ case 0: ++ regmap_update_bits(kcs_aspeed->map, HICR0, HICR0_LPC1E, enable * HICR0_LPC1E); ++ break; + case 1: +- regmap_update_bits(priv->map, LPC_HICR0, LPC_HICR0_LPC1E, enable * LPC_HICR0_LPC1E); +- return; ++ regmap_update_bits(kcs_aspeed->map, HICR0, HICR0_LPC2E, enable * HICR0_LPC2E); ++ break; + case 2: +- regmap_update_bits(priv->map, LPC_HICR0, LPC_HICR0_LPC2E, enable * LPC_HICR0_LPC2E); +- return; ++ regmap_update_bits(kcs_aspeed->map, HICR0, HICR0_LPC3E, enable * HICR0_LPC3E); ++ regmap_update_bits(kcs_aspeed->map, HICR4, HICR4_KCSENBL, enable * HICR4_KCSENBL); ++ break; + case 3: +- regmap_update_bits(priv->map, LPC_HICR0, LPC_HICR0_LPC3E, enable * LPC_HICR0_LPC3E); +- regmap_update_bits(priv->map, LPC_HICR4, +- LPC_HICR4_KCSENBL, enable * LPC_HICR4_KCSENBL); +- return; +- case 4: +- regmap_update_bits(priv->map, LPC_HICRB, LPC_HICRB_LPC4E, enable * LPC_HICRB_LPC4E); +- return; ++ regmap_update_bits(kcs_aspeed->map, HICRB, HICRB_LPC4E, enable * HICRB_LPC4E); ++ break; + default: +- pr_warn("%s: Unsupported channel: %d", __func__, kcs_bmc->channel); +- return; ++ return -EINVAL; + } + -+ 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 0; + } + + static void aspeed_kcs_check_obe(struct timer_list *timer) + { +- struct aspeed_kcs_bmc *priv = container_of(timer, struct aspeed_kcs_bmc, obe.timer); ++ struct aspeed_kcs_bmc *kcs_aspeed = container_of(timer, struct aspeed_kcs_bmc, obe.timer); + unsigned long flags; + u8 str; + +- spin_lock_irqsave(&priv->obe.lock, flags); +- if (priv->obe.remove) { +- spin_unlock_irqrestore(&priv->obe.lock, flags); ++ spin_lock_irqsave(&kcs_aspeed->obe.lock, flags); ++ if (kcs_aspeed->obe.remove) { ++ spin_unlock_irqrestore(&kcs_aspeed->obe.lock, flags); + return; + } + +- str = aspeed_kcs_inb(&priv->kcs_bmc, priv->kcs_bmc.ioreg.str); ++ str = aspeed_kcs_inb(&kcs_aspeed->kcs_bmc, kcs_aspeed->kcs_bmc.ioreg.str); + if (str & KCS_BMC_STR_OBF) { +- mod_timer(timer, jiffies + OBE_POLL_PERIOD); +- spin_unlock_irqrestore(&priv->obe.lock, flags); ++ mod_timer(timer, jiffies + KCS_OBE_POLL_PERIOD); ++ spin_unlock_irqrestore(&kcs_aspeed->obe.lock, flags); + return; + } +- spin_unlock_irqrestore(&priv->obe.lock, flags); +- +- kcs_bmc_handle_event(&priv->kcs_bmc); +-} +- +-static void aspeed_kcs_irq_mask_update(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 state) +-{ +- struct aspeed_kcs_bmc *priv = 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, +- &priv->kcs_bmc, priv->kcs_bmc.ioreg.str); +- /* Time for the slow path? */ +- if (rc == -ETIMEDOUT) +- mod_timer(&priv->obe.timer, jiffies + OBE_POLL_PERIOD); +- } else { +- del_timer(&priv->obe.timer); +- } +- } ++ spin_unlock_irqrestore(&kcs_aspeed->obe.lock, flags); + +- if (mask & KCS_BMC_EVENT_TYPE_IBF) { +- const bool enable = !!(state & KCS_BMC_EVENT_TYPE_IBF); +- +- switch (kcs_bmc->channel) { +- case 1: +- regmap_update_bits(priv->map, LPC_HICR2, LPC_HICR2_IBFIE1, +- enable * LPC_HICR2_IBFIE1); +- return; +- case 2: +- regmap_update_bits(priv->map, LPC_HICR2, LPC_HICR2_IBFIE2, +- enable * LPC_HICR2_IBFIE2); +- return; +- case 3: +- regmap_update_bits(priv->map, LPC_HICR2, LPC_HICR2_IBFIE3, +- enable * LPC_HICR2_IBFIE3); +- return; +- case 4: +- regmap_update_bits(priv->map, LPC_HICRB, LPC_HICRB_IBFIE4, +- enable * LPC_HICRB_IBFIE4); +- return; +- default: +- pr_warn("%s: Unsupported channel: %d", __func__, kcs_bmc->channel); +- return; +- } +- } ++ kcs_bmc_handle_event(&kcs_aspeed->kcs_bmc); + } + +-static const struct kcs_bmc_device_ops aspeed_kcs_ops = { +- .irq_mask_update = aspeed_kcs_irq_mask_update, +- .io_inputb = aspeed_kcs_inb, +- .io_outputb = aspeed_kcs_outb, +- .io_updateb = aspeed_kcs_updateb, +-}; +- +-static irqreturn_t aspeed_kcs_irq(int irq, void *arg) ++static irqreturn_t aspeed_kcs_isr(int irq, void *arg) + { + struct kcs_bmc_device *kcs_bmc = arg; + + return kcs_bmc_handle_event(kcs_bmc); + } + +-static int aspeed_kcs_config_downstream_irq(struct kcs_bmc_device *kcs_bmc, +- struct platform_device *pdev) ++static int aspeed_kcs_probe(struct platform_device *pdev) + { +- struct device *dev = &pdev->dev; +- int irq; ++ struct aspeed_kcs_bmc *kcs_aspeed; ++ struct kcs_bmc_device *kcs_bmc; ++ struct device *dev; ++ const __be32 *reg; ++ int i, rc, chan; + +- irq = platform_get_irq(pdev, 0); +- if (irq < 0) +- return irq; +- +- return devm_request_irq(dev, irq, aspeed_kcs_irq, IRQF_SHARED, +- dev_name(dev), kcs_bmc); +-} ++ dev = &pdev->dev; + +-static const struct kcs_ioreg ast_kcs_bmc_ioregs[KCS_CHANNEL_MAX] = { +- { .idr = LPC_IDR1, .odr = LPC_ODR1, .str = LPC_STR1 }, +- { .idr = LPC_IDR2, .odr = LPC_ODR2, .str = LPC_STR2 }, +- { .idr = LPC_IDR3, .odr = LPC_ODR3, .str = LPC_STR3 }, +- { .idr = LPC_IDR4, .odr = LPC_ODR4, .str = LPC_STR4 }, +-}; ++ kcs_aspeed = devm_kzalloc(dev, sizeof(*kcs_aspeed), GFP_KERNEL); ++ if (!kcs_aspeed) ++ return -ENOMEM; + +-static int aspeed_kcs_of_get_channel(struct platform_device *pdev) +-{ +- struct device_node *np; +- struct kcs_ioreg ioreg; +- const __be32 *reg; +- int i; ++ kcs_bmc = &kcs_aspeed->kcs_bmc; ++ kcs_bmc->ops = &aspeed_kcs_ops; ++ kcs_bmc->dev = dev; + +- np = pdev->dev.of_node; ++ kcs_aspeed->map = syscon_node_to_regmap(pdev->dev.parent->of_node); ++ if (IS_ERR(kcs_aspeed->map)) { ++ dev_err(&pdev->dev, "cannot get regmap\n"); ++ return -ENODEV; + } + +- /* Don't translate addresses, we want offsets for the regmaps */ +- reg = of_get_address(np, 0, NULL, NULL); +- if (!reg) +- return -EINVAL; +- ioreg.idr = be32_to_cpup(reg); ++ kcs_aspeed->irq = platform_get_irq(pdev, 0); ++ if (kcs_aspeed->irq < 0) { ++ dev_err(dev, "cannot get IRQ number\n"); ++ return kcs_aspeed->irq; ++ } + +- reg = of_get_address(np, 1, NULL, NULL); +- if (!reg) +- return -EINVAL; +- ioreg.odr = be32_to_cpup(reg); ++ reg = of_get_address(dev->of_node, 0, NULL, NULL); ++ if (!reg) { ++ dev_err(dev, "cannot get IDR\n"); ++ return -ENODEV; ++ } + +- reg = of_get_address(np, 2, NULL, NULL); +- if (!reg) +- return -EINVAL; +- ioreg.str = be32_to_cpup(reg); ++ kcs_bmc->ioreg.idr = be32_to_cpup(reg); + +- for (i = 0; i < ARRAY_SIZE(ast_kcs_bmc_ioregs); i++) { +- if (!memcmp(&ast_kcs_bmc_ioregs[i], &ioreg, sizeof(ioreg))) +- return i + 1; ++ reg = of_get_address(dev->of_node, 1, NULL, NULL); ++ if (!reg) { ++ dev_err(dev, "cannot get ODR\n"); ++ return -ENODEV; + } +- return -EINVAL; +-} + +-static int +-aspeed_kcs_of_get_io_address(struct platform_device *pdev, u32 addrs[2]) +-{ +- int rc; ++ kcs_bmc->ioreg.odr = be32_to_cpup(reg); + +- rc = of_property_read_variable_u32_array(pdev->dev.of_node, +- "aspeed,lpc-io-reg", +- addrs, 1, 2); +- if (rc < 0) { +- dev_err(&pdev->dev, "No valid 'aspeed,lpc-io-reg' configured\n"); +- return rc; ++ reg = of_get_address(dev->of_node, 2, NULL, NULL); ++ if (!reg) { ++ dev_err(dev, "cannot get STR\n"); ++ return -ENODEV; + } + +- if (addrs[0] > 0xffff) { +- dev_err(&pdev->dev, "Invalid data address in 'aspeed,lpc-io-reg'\n"); +- return -EINVAL; ++ kcs_bmc->ioreg.str = be32_to_cpup(reg); + -+ 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); -+} ++ for (i = 0; i < KCS_HW_INSTANCE_NUM; ++i) { ++ if (aspeed_kcs_ioregs[i].idr == kcs_bmc->ioreg.idr && ++ aspeed_kcs_ioregs[i].odr == kcs_bmc->ioreg.odr && ++ aspeed_kcs_ioregs[i].str == kcs_bmc->ioreg.str) { ++ kcs_aspeed->hw_inst = i; ++ break; ++ } + } + +- if (rc == 2 && addrs[1] > 0xffff) { +- dev_err(&pdev->dev, "Invalid status address in 'aspeed,lpc-io-reg'\n"); ++ if (i >= KCS_HW_INSTANCE_NUM) { ++ dev_err(dev, "invalid IDR/ODR/STR register\n"); + return -EINVAL; + } + +- return rc; +-} +- +-static int aspeed_kcs_probe(struct platform_device *pdev) +-{ +- struct kcs_bmc_device *kcs_bmc; +- struct aspeed_kcs_bmc *priv; +- struct device_node *np; +- bool have_upstream_irq; +- u32 upstream_irq[2]; +- int rc, channel; +- int nr_addrs; +- u32 addrs[2]; +- +- np = pdev->dev.of_node->parent; +- if (!of_device_is_compatible(np, "aspeed,ast2400-lpc-v2") && +- !of_device_is_compatible(np, "aspeed,ast2500-lpc-v2") && +- !of_device_is_compatible(np, "aspeed,ast2600-lpc-v2")) { +- dev_err(&pdev->dev, "unsupported LPC device binding\n"); ++ rc = of_property_read_u32(dev->of_node, "kcs-io-addr", &kcs_aspeed->io_addr); ++ if (rc || kcs_aspeed->io_addr > (USHRT_MAX - 1)) { ++ dev_err(dev, "invalid IO address\n"); + return -ENODEV; + } + +- channel = aspeed_kcs_of_get_channel(pdev); +- if (channel < 0) +- return channel; +- +- nr_addrs = aspeed_kcs_of_get_io_address(pdev, addrs); +- if (nr_addrs < 0) +- return nr_addrs; +- +- np = pdev->dev.of_node; +- rc = of_property_read_u32_array(np, "aspeed,lpc-interrupts", upstream_irq, 2); +- if (rc && rc != -EINVAL) +- return -EINVAL; +- +- have_upstream_irq = !rc; ++ rc = of_property_read_u32(dev->of_node, "kcs-channel", &chan); ++ if (rc) { ++ chan = ida_alloc(&aspeed_kcs_bmc_ida, GFP_KERNEL); ++ if (chan < 0) { ++ dev_err(dev, "cannot allocate ID for KCS channel\n"); ++ return chan; ++ } ++ } + +- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); +- if (!priv) +- return -ENOMEM; ++ kcs_bmc->channel = chan; + +- kcs_bmc = &priv->kcs_bmc; +- kcs_bmc->dev = &pdev->dev; +- kcs_bmc->channel = channel; +- kcs_bmc->ioreg = ast_kcs_bmc_ioregs[channel - 1]; +- kcs_bmc->ops = &aspeed_kcs_ops; ++ rc = of_property_read_u32_array(dev->of_node, "kcs-upstream-serirq", (u32 *)&kcs_aspeed->sirq, 2); ++ if (rc) { ++ kcs_aspeed->sirq.type = IRQ_TYPE_NONE; ++ } else { ++ if (kcs_aspeed->sirq.id > 15) { ++ dev_err(dev, "invalid SerIRQ number, expected sirq <= 15\n"); ++ return -EINVAL; ++ } + +- priv->map = syscon_node_to_regmap(pdev->dev.parent->of_node); +- if (IS_ERR(priv->map)) { +- dev_err(&pdev->dev, "Couldn't get regmap\n"); +- return -ENODEV; ++ if (kcs_aspeed->sirq.type != IRQ_TYPE_LEVEL_HIGH && ++ kcs_aspeed->sirq.type != IRQ_TYPE_LEVEL_LOW) { ++ dev_err(dev, "invalid SerIRQ type, expected IRQ_TYPE_LEVEL_HIGH/LOW only\n"); ++ return -EINVAL; ++ } + } + +- spin_lock_init(&priv->obe.lock); +- priv->obe.remove = false; +- timer_setup(&priv->obe.timer, aspeed_kcs_check_obe, 0); ++ timer_setup(&kcs_aspeed->obe.timer, aspeed_kcs_check_obe, 0); ++ spin_lock_init(&kcs_aspeed->obe.lock); ++ kcs_aspeed->obe.remove = false; + +- rc = aspeed_kcs_set_address(kcs_bmc, addrs, nr_addrs); ++ aspeed_kcs_irq_mask_update(kcs_bmc, (KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE), 0); + -+static int aspeed_trng_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct aspeed_trng *priv; -+ struct resource *res; -+ int ret; ++ rc = aspeed_kcs_config_io_address(kcs_aspeed); + if (rc) + return rc; + +- /* Host to BMC IRQ */ +- rc = aspeed_kcs_config_downstream_irq(kcs_bmc, pdev); ++ rc = aspeed_kcs_config_upstream_serirq(kcs_aspeed); + if (rc) + return rc; + +- /* BMC to Host IRQ */ +- if (have_upstream_irq) { +- rc = aspeed_kcs_config_upstream_irq(priv, upstream_irq[0], upstream_irq[1]); +- if (rc < 0) +- return rc; +- } else { +- priv->upstream_irq.mode = aspeed_kcs_irq_none; ++ rc = devm_request_irq(dev, kcs_aspeed->irq, aspeed_kcs_isr, IRQF_SHARED, ++ dev_name(dev), kcs_bmc); ++ if (rc) { ++ dev_err(dev, "cannot request IRQ\n"); ++ return rc; + } + +- platform_set_drvdata(pdev, priv); ++ platform_set_drvdata(pdev, kcs_aspeed); + +- aspeed_kcs_irq_mask_update(kcs_bmc, (KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE), 0); +- aspeed_kcs_enable_channel(kcs_bmc, true); ++ rc = aspeed_kcs_enable_channel(kcs_aspeed, true); ++ if (rc) { ++ dev_err(dev, "cannot enable channel %d: %d\n", ++ kcs_bmc->channel, rc); ++ return rc; ++ } + +- rc = kcs_bmc_add_device(&priv->kcs_bmc); ++ rc = kcs_bmc_add_device(kcs_bmc); + if (rc) { +- dev_warn(&pdev->dev, "Failed to register channel %d: %d\n", kcs_bmc->channel, rc); ++ dev_warn(dev, "cannot register channel %d: %d\n", ++ kcs_bmc->channel, rc); + return rc; + } + +- dev_info(&pdev->dev, "Initialised channel %d at 0x%x\n", +- kcs_bmc->channel, addrs[0]); ++ dev_info(dev, "Initialised channel %d at IO address 0x%x\n", ++ kcs_bmc->channel, kcs_aspeed->io_addr); + + return 0; + } + + static void aspeed_kcs_remove(struct platform_device *pdev) + { +- struct aspeed_kcs_bmc *priv = platform_get_drvdata(pdev); +- struct kcs_bmc_device *kcs_bmc = &priv->kcs_bmc; ++ struct aspeed_kcs_bmc *kcs_aspeed = platform_get_drvdata(pdev); ++ struct kcs_bmc_device *kcs_bmc = &kcs_aspeed->kcs_bmc; + + kcs_bmc_remove_device(kcs_bmc); + +- aspeed_kcs_enable_channel(kcs_bmc, false); ++ aspeed_kcs_enable_channel(kcs_aspeed, false); + aspeed_kcs_irq_mask_update(kcs_bmc, (KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE), 0); + + /* Make sure it's proper dead */ +- spin_lock_irq(&priv->obe.lock); +- priv->obe.remove = true; +- spin_unlock_irq(&priv->obe.lock); +- del_timer_sync(&priv->obe.timer); ++ spin_lock_irq(&kcs_aspeed->obe.lock); ++ kcs_aspeed->obe.remove = true; ++ spin_unlock_irq(&kcs_aspeed->obe.lock); ++ del_timer_sync(&kcs_aspeed->obe.timer); + } + +-static const struct of_device_id ast_kcs_bmc_match[] = { +- { .compatible = "aspeed,ast2400-kcs-bmc-v2" }, +- { .compatible = "aspeed,ast2500-kcs-bmc-v2" }, ++static const struct of_device_id aspeed_kcs_bmc_match[] = { ++ { .compatible = "aspeed,ast2400-kcs-bmc" }, ++ { .compatible = "aspeed,ast2500-kcs-bmc" }, + { .compatible = "aspeed,ast2600-kcs-bmc" }, + { } + }; +-MODULE_DEVICE_TABLE(of, ast_kcs_bmc_match); ++MODULE_DEVICE_TABLE(of, aspeed_kcs_bmc_match); + +-static struct platform_driver ast_kcs_bmc_driver = { ++static struct platform_driver aspeed_kcs_bmc_driver = { + .driver = { +- .name = DEVICE_NAME, +- .of_match_table = ast_kcs_bmc_match, ++ .name = DEVICE_NAME, ++ .of_match_table = aspeed_kcs_bmc_match, + }, +- .probe = aspeed_kcs_probe, +- .remove_new = aspeed_kcs_remove, ++ .probe = aspeed_kcs_probe, ++ .remove = aspeed_kcs_remove, + }; +-module_platform_driver(ast_kcs_bmc_driver); ++module_platform_driver(aspeed_kcs_bmc_driver); + + MODULE_LICENSE("GPL v2"); + MODULE_AUTHOR("Haiyue Wang "); + 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. + -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; ++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. + -+ 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); + config COMMON_CLK_S2MPS11 + tristate "Clock driver for S2MPS1X/S5M8767 MFD" + depends on MFD_SEC_CORE || COMPILE_TEST +@@ -342,6 +356,14 @@ + This driver supports the clocking features of the Cirrus Logic + Lochnagar audio development board. + ++config COMMON_CLK_NPCM8XX ++ tristate "Clock driver for the NPCM8XX SoC Family" ++ depends on ARCH_NPCM || COMPILE_TEST ++ help ++ This driver supports the clocks on the Nuvoton BMC NPCM8XX SoC Family, ++ all the clocks are initialized by the bootloader, so this driver ++ allows only reading of current settings directly from the hardware. + -+ priv->rng.name = pdev->name; -+ priv->rng.quality = 900; -+ priv->rng.read = aspeed_trng_read; + config COMMON_CLK_LOONGSON2 + bool "Clock driver for Loongson-2 SoC" + depends on LOONGARCH || 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 +@@ -62,6 +64,7 @@ + obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o + obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o + obj-$(CONFIG_ARCH_NPCM7XX) += clk-npcm7xx.o ++obj-$(CONFIG_COMMON_CLK_NPCM8XX) += clk-npcm8xx.o + obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o + obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o + obj-$(CONFIG_CLK_LS1028A_PLLDIG) += clk-plldig.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 +@@ -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 }, + [ASPEED_CLK_GATE_USBPORT2CLK] = { 7, 3, "usb-port2-gate", NULL, 0 }, /* USB2.0 Host port 2 */ +- [ASPEED_CLK_GATE_LCLK] = { 8, 5, "lclk-gate", NULL, 0 }, /* LPC */ ++ [ASPEED_CLK_GATE_LCLK] = { 8, 5, "lclk-gate", NULL, CLK_IS_CRITICAL }, /* LPC */ + [ASPEED_CLK_GATE_USBUHCICLK] = { 9, 15, "usb-uhci-gate", NULL, 0 }, /* USB1.1 (requires port 2 enabled) */ + [ASPEED_CLK_GATE_D1CLK] = { 10, 13, "d1clk-gate", NULL, 0 }, /* GFX CRT */ + [ASPEED_CLK_GATE_YCLK] = { 13, 4, "yclk-gate", NULL, 0 }, /* HAC */ + [ASPEED_CLK_GATE_USBPORT1CLK] = { 14, 14, "usb-port1-gate", NULL, 0 }, /* USB2 hub/USB2 host port 1/USB1.1 dev */ +- [ASPEED_CLK_GATE_UART1CLK] = { 15, -1, "uart1clk-gate", "uart", 0 }, /* UART1 */ +- [ASPEED_CLK_GATE_UART2CLK] = { 16, -1, "uart2clk-gate", "uart", 0 }, /* UART2 */ ++ [ASPEED_CLK_GATE_UART1CLK] = { 15, -1, "uart1clk-gate", "uart", CLK_IS_CRITICAL }, /* UART1 */ ++ [ASPEED_CLK_GATE_UART2CLK] = { 16, -1, "uart2clk-gate", "uart", CLK_IS_CRITICAL }, /* UART2 */ + [ASPEED_CLK_GATE_UART5CLK] = { 17, -1, "uart5clk-gate", "uart", 0 }, /* UART5 */ +- [ASPEED_CLK_GATE_ESPICLK] = { 19, -1, "espiclk-gate", NULL, 0 }, /* eSPI */ ++ [ASPEED_CLK_GATE_ESPICLK] = { 19, -1, "espiclk-gate", NULL, CLK_IS_CRITICAL }, /* eSPI */ + [ASPEED_CLK_GATE_MAC1CLK] = { 20, 11, "mac1clk-gate", "mac", 0 }, /* MAC1 */ + [ASPEED_CLK_GATE_MAC2CLK] = { 21, 12, "mac2clk-gate", "mac", 0 }, /* MAC2 */ + [ASPEED_CLK_GATE_RSACLK] = { 24, -1, "rsaclk-gate", NULL, 0 }, /* RSA */ +@@ -278,6 +278,7 @@ + [ASPEED_RESET_PECI] = 10, + [ASPEED_RESET_I2C] = 2, + [ASPEED_RESET_AHB] = 1, ++ [ASPEED_RESET_VIDEO] = 6, + + /* + * 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 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++// Copyright ASPEED Technology + -+ aspeed_trng_enable(priv); ++#include ++#include ++#include ++#include + -+ ret = devm_hwrng_register(&pdev->dev, &priv->rng); -+ if (ret) -+ return ret; ++#include ++#include + -+ platform_set_drvdata(pdev, priv); ++#define AST1700_CLK_25MHZ 25000000 ++#define AST1700_CLK_24MHZ 24000000 ++#define AST1700_CLK_192MHZ 192000000 ++/* IO Die */ ++#define AST1700_CLK_STOP 0x240 ++#define AST1700_CLK_STOP2 0x260 ++#define AST1700_CLK_SEL1 0x280 ++#define AST1700_CLK_SEL2 0x284 ++#define UXCLK_MASK GENMASK(1, 0) ++#define HUXCLK_MASK GENMASK(4, 3) ++#define AST1700_HPLL_PARAM 0x300 ++#define AST1700_APLL_PARAM 0x310 ++#define AST1700_DPLL_PARAM 0x320 ++#define AST1700_UXCLK_CTRL 0x330 ++#define AST1700_HUXCLK_CTRL 0x334 + -+ dev_info(dev, "Aspeed Hardware RNG successfully registered\n"); ++static DEFINE_IDA(ast1700_clk_ida); + -+ return 0; -+} ++/* Globally visible clocks */ ++static DEFINE_SPINLOCK(ast1700_clk_lock); + -+static void aspeed_trng_remove(struct platform_device *pdev) ++/* Division of RGMII Clock */ ++static const struct clk_div_table ast1700_rgmii_div_table[] = { ++ { 0x0, 4 }, ++ { 0x1, 4 }, ++ { 0x2, 6 }, ++ { 0x3, 8 }, ++ { 0x4, 10 }, ++ { 0x5, 12 }, ++ { 0x6, 14 }, ++ { 0x7, 16 }, ++ { 0 } ++}; ++ ++/* Division of RMII Clock */ ++static const struct clk_div_table ast1700_rmii_div_table[] = { ++ { 0x0, 8 }, ++ { 0x1, 8 }, ++ { 0x2, 12 }, ++ { 0x3, 16 }, ++ { 0x4, 20 }, ++ { 0x5, 24 }, ++ { 0x6, 28 }, ++ { 0x7, 32 }, ++ { 0 } ++}; ++ ++/* Division of HCLK/SDIO/MAC/apll_divn CLK */ ++static const struct clk_div_table ast1700_clk_div_table[] = { ++ { 0x0, 2 }, ++ { 0x1, 2 }, ++ { 0x2, 3 }, ++ { 0x3, 4 }, ++ { 0x4, 5 }, ++ { 0x5, 6 }, ++ { 0x6, 7 }, ++ { 0x7, 8 }, ++ { 0 } ++}; ++ ++/* Division of PCLK/EMMC CLK */ ++static const struct clk_div_table ast1700_clk_div_table2[] = { ++ { 0x0, 2 }, ++ { 0x1, 4 }, ++ { 0x2, 6 }, ++ { 0x3, 8 }, ++ { 0x4, 10 }, ++ { 0x5, 12 }, ++ { 0x6, 14 }, ++ { 0x7, 16 }, ++ { 0 } ++}; ++ ++static struct clk_hw *AST1700_calc_uclk(const char *name, u32 val) +{ -+ struct aspeed_trng *priv = platform_get_drvdata(pdev); ++ unsigned int mult, div; + -+ aspeed_trng_disable(priv); -+} ++ /* UARTCLK = UXCLK * R / (N * 2) */ ++ u32 r = val & 0xff; ++ u32 n = (val >> 8) & 0x3ff; + -+static const struct of_device_id aspeed_trng_dt_ids[] = { -+ { .compatible = "aspeed,ast2600-trng" }, -+ { .compatible = "aspeed,ast2700-trng" }, -+ {} ++ mult = r; ++ div = n * 2; ++ ++ return clk_hw_register_fixed_factor(NULL, name, "ast1700-uxclk", 0, mult, div); +}; -+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, -+ }, ++static struct clk_hw *AST1700_calc_huclk(const char *name, u32 val) ++{ ++ unsigned int mult, div; ++ ++ /* UARTCLK = UXCLK * R / (N * 2) */ ++ u32 r = val & 0xff; ++ u32 n = (val >> 8) & 0x3ff; ++ ++ mult = r; ++ div = n * 2; ++ ++ return clk_hw_register_fixed_factor(NULL, name, "ast1700-huxclk", 0, mult, div); +}; + -+module_platform_driver(aspeed_trng_driver); ++static struct clk_hw *AST1700_calc_pll(const char *name, const char *parent_name, u32 val) ++{ ++ unsigned int mult, div; + -+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 2026-04-08 18:03:46.629736033 +0000 -@@ -0,0 +1,18 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+# -+# DWC Hardware Random Number Generator (RNG) configuration -+# ++ if (val & BIT(24)) { ++ /* Pass through mode */ ++ mult = 1; ++ div = 1; ++ } else { ++ /* F = 25Mhz * [(M + 1) / (n + 1)] / (p + 1) */ ++ u32 m = val & 0x1fff; ++ u32 n = (val >> 13) & 0x3f; ++ u32 p = (val >> 19) & 0xf; + -+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. ++ mult = (m + 1) / (n + 1); ++ div = (p + 1); ++ } ++ return clk_hw_register_fixed_factor(NULL, name, parent_name, 0, mult, div); ++} + -+ To compile this driver as a module, choose M here. the -+ module will be called dwc-rng. ++static int AST1700_clk_is_enabled(struct clk_hw *hw) ++{ ++ struct clk_gate *gate = to_clk_gate(hw); ++ u32 clk = BIT(gate->bit_idx); ++ u32 reg; + -+ If unsure, say Y. ++ reg = readl(gate->reg); + -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-04-08 18:03:46.629736033 +0000 -@@ -0,0 +1,22 @@ -+# SPDX-License-Identifier: GPL-2.0 ++ return !(reg & clk); ++} + -+ccflags-y := -I $(srctree)/drivers/char/hw_random/dwc/src/trng/include \ -+ -I $(srctree)/drivers/char/hw_random/dwc/src/pdu/linux/include ++static int AST1700_clk_enable(struct clk_hw *hw) ++{ ++ struct clk_gate *gate = to_clk_gate(hw); ++ u32 clk = BIT(gate->bit_idx); + -+obj-$(CONFIG_HW_RANDOM_DWC) += elppdu.o -+elppdu-objs := src/pdu/linux/kernel/pdu.o \ -+ src/pdu/common/pdu/pdu_dev32.o \ ++ if (readl(gate->reg) & clk) ++ writel(clk, gate->reg + 0x04); + -+obj-$(CONFIG_HW_RANDOM_DWC) += elpmem.o -+elpmem-objs := src/pdu/linux/kernel/spacc_mem.o \ ++ return 0; ++} + -+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 \ ++static void AST1700_clk_disable(struct clk_hw *hw) ++{ ++ struct clk_gate *gate = to_clk_gate(hw); ++ u32 clk = BIT(gate->bit_idx); + -+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-04-08 18:03:46.629736033 +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_ ++ /* Clock is set to enable, so use write to set register */ ++ writel(clk, gate->reg); ++} + -+/* -+ * Common error definitions. Be sure to update pdu_error_code when changing -+ * anything in this list. -+ */ ++static const struct clk_ops AST1700_clk_gate_ops = { ++ .enable = AST1700_clk_enable, ++ .disable = AST1700_clk_disable, ++ .is_enabled = AST1700_clk_is_enabled, ++}; + -+#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) ++static struct clk_hw *AST1700_clk_hw_register_gate(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 clock_idx, ++ u8 clk_gate_flags, spinlock_t *lock) ++{ ++ struct clk_gate *gate; ++ struct clk_hw *hw; ++ struct clk_init_data init; ++ int ret = -EINVAL; + -+#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-04-08 18:03:46.629736033 +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. -+ */ ++ gate = kzalloc(sizeof(*gate), GFP_KERNEL); ++ if (!gate) ++ return ERR_PTR(-ENOMEM); + -+#include "elppdu.h" ++ init.name = name; ++ init.ops = &AST1700_clk_gate_ops; ++ init.flags = flags; ++ init.parent_names = parent_name ? &parent_name : NULL; ++ init.num_parents = parent_name ? 1 : 0; + -+void pdu_to_dev32(void *addr_, u32 *src, unsigned long nword) -+{ -+ unsigned char *addr = addr_; ++ gate->reg = reg; ++ gate->bit_idx = clock_idx; ++ gate->flags = clk_gate_flags; ++ gate->lock = lock; ++ gate->hw.init = &init; + -+ while (nword--) { -+ pdu_io_write32(addr, *src++); -+ addr += 4; ++ hw = &gate->hw; ++ ret = clk_hw_register(dev, hw); ++ if (ret) { ++ kfree(gate); ++ hw = ERR_PTR(ret); + } ++ ++ return hw; +} -+EXPORT_SYMBOL(pdu_to_dev32); + -+void pdu_from_dev32(u32 *dst, void *addr_, unsigned long nword) -+{ -+ unsigned char *addr = addr_; ++struct ast1700_reset { ++ void __iomem *base; ++ struct reset_controller_dev rcdev; ++}; + -+ while (nword--) { -+ *dst++ = pdu_io_read32(addr); -+ addr += 4; -+ } -+} -+EXPORT_SYMBOL(pdu_from_dev32); ++#define to_rc_data(p) container_of(p, struct ast1700_reset, rcdev) + -+void pdu_to_dev32_big(void *addr_, const unsigned char *src, -+ unsigned long nword) ++static int ast1700_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) +{ -+ unsigned char *addr = addr_; -+ unsigned long v; ++ struct ast1700_reset *rc = to_rc_data(rcdev); ++ u32 rst = BIT(id % 32); ++ u32 reg = id >= 32 ? 0x220 : 0x200; + -+ 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; -+ } ++ writel(rst, rc->base + reg); ++ return 0; +} -+EXPORT_SYMBOL(pdu_to_dev32_big); + -+void pdu_from_dev32_big(unsigned char *dst, void *addr_, unsigned long nword) ++static int ast1700_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) +{ -+ unsigned char *addr = addr_; -+ unsigned long v; ++ struct ast1700_reset *rc = to_rc_data(rcdev); ++ u32 rst = BIT(id % 32); ++ u32 reg = id >= 32 ? 0x220 : 0x200; + -+ 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; -+ } ++ /* Use set to clear register */ ++ writel(rst, rc->base + reg + 0x04); ++ return 0; +} -+EXPORT_SYMBOL(pdu_from_dev32_big); + -+void pdu_to_dev32_little(void *addr_, const unsigned char *src, -+ unsigned long nword) ++static int ast1700_reset_status(struct reset_controller_dev *rcdev, unsigned long id) +{ -+ unsigned char *addr = addr_; -+ unsigned long v; ++ struct ast1700_reset *rc = to_rc_data(rcdev); ++ u32 rst = BIT(id % 32); ++ u32 reg = id >= 32 ? 0x220 : 0x200; + -+ 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; -+ } ++ return (readl(rc->base + reg) & rst); +} -+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; ++static const struct reset_control_ops ast1700_reset_ops = { ++ .assert = ast1700_reset_assert, ++ .deassert = ast1700_reset_deassert, ++ .status = ast1700_reset_status, ++}; + -+ 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); ++static const char *const sdclk_sel0[] = { ++ "ast1700_0-hpll_divn", ++ "ast1700_0-apll_divn", ++}; + -+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); ++static const char *const sdclk_sel1[] = { ++ "ast1700_1-hpll_divn", ++ "ast1700_1-apll_divn", ++}; + -+void pdu_from_dev32_s(unsigned char *dst, void *addr, unsigned long nword, -+ int endian) ++static const char *const uartclk_sel0[] = { ++ "ast1700_0-uartxclk", ++ "ast1700_0-huartxclk", ++}; ++ ++static const char *const uartclk_sel1[] = { ++ "ast1700_1-uartxclk", ++ "ast1700_1-huartxclk", ++}; ++ ++static const char *const uxclk_sel0[] = { ++ "ast1700_0-apll_div4", ++ "ast1700_0-apll_div2", ++ "ast1700_0-apll", ++ "ast1700_0-hpll", ++}; ++ ++static const char *const uxclk_sel1[] = { ++ "ast1700_1-apll_div4", ++ "ast1700_1-apll_div2", ++ "ast1700_1-apll", ++ "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) +{ -+ 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-04-08 18:03:46.629736033 +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. -+ */ ++ struct clk_hw_onecell_data *clk_data; ++ struct ast1700_reset *reset; ++ u32 uart_clk_source = 0; ++ void __iomem *clk_base; ++ struct clk_hw **clks; ++ struct clk_hw *hw; ++ u32 val; ++ int ret; + -+#ifndef SYNPDU_H_ -+#define SYNPDU_H_ ++ int id = ida_simple_get(&ast1700_clk_ida, 0, 0, GFP_KERNEL); + -+/* Platform Specific */ -+#include /* printk() */ -+#include /* size_t */ -+#include /* memcpy()/etc */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++ clk_base = of_iomap(ast1700_node, 0); ++ WARN_ON(!clk_base); + -+#ifndef PDU_BASE_ADDR -+#define PDU_BASE_ADDR 0x14c3b000 -+#endif ++ clk_data = kzalloc(struct_size(clk_data, hws, AST1700_NUM_CLKS), GFP_KERNEL); ++ if (!clk_data) ++ return -ENOMEM; + -+#ifndef PDU_BASE_IRQ -+#define PDU_BASE_IRQ 91 -+#endif ++ clk_data->num = AST1700_NUM_CLKS; ++ clks = clk_data->hws; + -+#define PDU_SINGLE_CORE 1 -+#define PDU_SINGLE_NIST_TRNG 1 ++ reset = kzalloc(sizeof(*reset), GFP_KERNEL); ++ if (!reset) ++ return -ENOMEM; + -+#if 1 -+#define SYNHW_PRINT printk -+#else -+#define SYNHW_PRINT(...) -+#endif ++ reset->base = clk_base; + -+#define CPU_YIELD -+#define SYNHW_MEMCPY memcpy ++ reset->rcdev.owner = THIS_MODULE; ++ reset->rcdev.nr_resets = AST1700_RESET_NUMS; ++ reset->rcdev.ops = &ast1700_reset_ops; ++ reset->rcdev.of_node = ast1700_node; + -+// 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 ++ ret = reset_controller_register(&reset->rcdev); ++ if (ret) { ++ pr_err("soc1 failed to register reset controller\n"); ++ return ret; ++ } ++ /* ++ * Ast1700 A0 workaround: ++ * I3C reset should assert all of the I3C controllers simultaneously. ++ * Otherwise, it may lead to failure in accessing I3C registers. ++ */ ++ if (!(readl(clk_base) & BIT(16))) { ++ for (int i = AST1700_RESET_I3C0; i <= AST1700_RESET_I3C15; i++) ++ ast1700_reset_assert(&reset->rcdev, i); ++ } + -+// Locking -+#define PDU_LOCK_TYPE spinlock_t -+#define PDU_INIT_LOCK(lock) spin_lock_init(lock) ++ hw = clk_hw_register_fixed_rate(NULL, CREATE_CLK_NAME(id, "clkin"), NULL, 0, AST1700_CLK_25MHZ); ++ if (IS_ERR(hw)) ++ return PTR_ERR(hw); ++ clks[AST1700_CLKIN] = hw; + -+// 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) ++ /* HPLL 1000Mhz */ ++ val = readl(clk_base + AST1700_HPLL_PARAM); ++ clks[AST1700_CLK_HPLL] = AST1700_calc_pll(CREATE_CLK_NAME(id, "hpll"), CREATE_CLK_NAME(id, "clkin"), val); + -+// 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) ++ /* HPLL 800Mhz */ ++ val = readl(clk_base + AST1700_APLL_PARAM); ++ clks[AST1700_CLK_APLL] = AST1700_calc_pll(CREATE_CLK_NAME(id, "apll"), CREATE_CLK_NAME(id, "clkin"), val); + -+#include "../../common/include/elppdu_error.h" ++ clks[AST1700_CLK_APLL_DIV2] = ++ clk_hw_register_fixed_factor(NULL, CREATE_CLK_NAME(id, "apll_div2"), CREATE_CLK_NAME(id, "apll"), 0, 1, 2); + -+void *pdu_linux_map_regs(struct device *dev, struct resource *regs); ++ clks[AST1700_CLK_APLL_DIV4] = ++ clk_hw_register_fixed_factor(NULL, CREATE_CLK_NAME(id, "apll_div4"), CREATE_CLK_NAME(id, "apll"), 0, 1, 4); + -+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); ++ val = readl(clk_base + AST1700_DPLL_PARAM); ++ clks[AST1700_CLK_DPLL] = AST1700_calc_pll(CREATE_CLK_NAME(id, "dpll"), CREATE_CLK_NAME(id, "clkin"), val); + -+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); ++ /* uxclk mux selection */ ++ clks[AST1700_CLK_UXCLK] = ++ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uxclk"), ++ (id == 0) ? uxclk_sel0 : uxclk_sel1, ++ (id == 0) ? ARRAY_SIZE(uxclk_sel0) : ARRAY_SIZE(uxclk_sel1), ++ 0, clk_base + AST1700_CLK_SEL2, ++ 0, 2, 0, &ast1700_clk_lock); + -+void *pdu_malloc(unsigned long n); -+void pdu_free(void *p); ++ val = readl(clk_base + AST1700_UXCLK_CTRL); ++ clks[AST1700_CLK_UARTX] = AST1700_calc_uclk(CREATE_CLK_NAME(id, "uartxclk"), val); + -+int pdu_error_code(int code); ++ /* huxclk mux selection */ ++ clks[AST1700_CLK_HUXCLK] = ++ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "huxclk"), ++ (id == 0) ? uxclk_sel0 : uxclk_sel1, ++ (id == 0) ? ARRAY_SIZE(uxclk_sel0) : ARRAY_SIZE(uxclk_sel1), ++ 0, clk_base + AST1700_CLK_SEL2, ++ 3, 2, 0, &ast1700_clk_lock); + -+#endif ++ val = readl(clk_base + AST1700_HUXCLK_CTRL); ++ clks[AST1700_CLK_HUARTX] = AST1700_calc_huclk(CREATE_CLK_NAME(id, "huartxclk"), val); + -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-04-08 18:03:46.629736033 +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 ++ /* AHB CLK = 200Mhz */ ++ clks[AST1700_CLK_AHB] = ++ clk_hw_register_divider_table(NULL, CREATE_CLK_NAME(id, "ahb"), ++ CREATE_CLK_NAME(id, "hpll"), ++ 0, clk_base + AST1700_CLK_SEL2, ++ 20, 3, 0, ast1700_clk_div_table, &ast1700_clk_lock); + -+#include "elppdu.h" ++ /* APB CLK = 100Mhz */ ++ clks[AST1700_CLK_APB] = ++ clk_hw_register_divider_table(NULL, CREATE_CLK_NAME(id, "apb"), ++ CREATE_CLK_NAME(id, "hpll"), ++ 0, clk_base + AST1700_CLK_SEL1, ++ 18, 3, 0, ast1700_clk_div_table2, &ast1700_clk_lock); + -+static bool trace_io; -+module_param(trace_io, bool, 0600); -+MODULE_PARM_DESC(trace_io, "Trace MMIO reads/writes"); ++ //rmii ++ clks[AST1700_CLK_RMII] = ++ clk_hw_register_divider_table(NULL, CREATE_CLK_NAME(id, "rmii"), ++ CREATE_CLK_NAME(id, "hpll"), ++ 0, clk_base + AST1700_CLK_SEL2, ++ 21, 3, 0, ast1700_rmii_div_table, &ast1700_clk_lock); + -+void *pdu_linux_map_regs(struct device *dev, struct resource *regs) -+{ -+ return devm_ioremap_resource(dev, regs); -+} -+EXPORT_SYMBOL(pdu_linux_map_regs); ++ //rgmii ++ clks[AST1700_CLK_RGMII] = ++ clk_hw_register_divider_table(NULL, CREATE_CLK_NAME(id, "rgmii"), ++ CREATE_CLK_NAME(id, "hpll"), ++ 0, clk_base + AST1700_CLK_SEL2, ++ 25, 3, 0, ast1700_rgmii_div_table, &ast1700_clk_lock); + -+void pdu_io_write32(void *addr, unsigned long val) -+{ -+ if (trace_io) -+ SYNHW_PRINT("PDU: write %.8lx -> %p\n", val, addr); ++ //mac hclk ++ clks[AST1700_CLK_MACHCLK] = ++ clk_hw_register_divider_table(NULL, CREATE_CLK_NAME(id, "machclk"), ++ CREATE_CLK_NAME(id, "hpll"), ++ 0, clk_base + AST1700_CLK_SEL2, ++ 29, 3, 0, ast1700_clk_div_table, &ast1700_clk_lock); + -+ writel(val, addr); -+} -+EXPORT_SYMBOL(pdu_io_write32); ++ clks[AST1700_CLK_GATE_LCLK0] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "lclk0-gate"), NULL, ++ CLK_IS_CRITICAL, clk_base + AST1700_CLK_STOP, ++ 0, 0, &ast1700_clk_lock); + -+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; -+ } ++ clks[AST1700_CLK_GATE_LCLK0] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "lclk1-gate"), NULL, ++ CLK_IS_CRITICAL, clk_base + AST1700_CLK_STOP, ++ 1, 0, &ast1700_clk_lock); + -+ *cache = val; -+ pdu_io_write32(addr, val); -+} -+EXPORT_SYMBOL(pdu_io_cached_write32); ++ clks[AST1700_CLK_GATE_ESPI0CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "espi0clk-gate"), NULL, ++ CLK_IS_CRITICAL, clk_base + AST1700_CLK_STOP, ++ 2, 0, &ast1700_clk_lock); + -+unsigned long pdu_io_read32(void *addr) -+{ -+ unsigned long val; ++ clks[AST1700_CLK_GATE_ESPI1CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "espi1clk-gate"), NULL, ++ CLK_IS_CRITICAL, clk_base + AST1700_CLK_STOP, ++ 3, 0, &ast1700_clk_lock); + -+ val = readl(addr); ++ //sd pll divn ++ clks[AST1700_CLK_HPLL_DIVN] = ++ clk_hw_register_divider_table(NULL, CREATE_CLK_NAME(id, "hpll_divn"), ++ CREATE_CLK_NAME(id, "hpll"), ++ 0, clk_base + AST1700_CLK_SEL2, ++ 20, 3, 0, ast1700_clk_div_table, &ast1700_clk_lock); + -+ if (trace_io) -+ SYNHW_PRINT("PDU: read %.8lx <- %p\n", val, addr); ++ clks[AST1700_CLK_APLL_DIVN] = ++ clk_hw_register_divider_table(NULL, CREATE_CLK_NAME(id, "apll_divn"), ++ CREATE_CLK_NAME(id, "apll"), ++ 0, clk_base + AST1700_CLK_SEL2, ++ 8, 3, 0, ast1700_clk_div_table, &ast1700_clk_lock); + -+ return val; -+} -+EXPORT_SYMBOL(pdu_io_read32); ++ //sd clk ++ clks[AST1700_CLK_SDCLK] = ++ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "sdclk"), ++ (id == 0) ? sdclk_sel0 : sdclk_sel1, ++ (id == 0) ? ARRAY_SIZE(sdclk_sel0) : ARRAY_SIZE(sdclk_sel1), ++ 0, clk_base + AST1700_CLK_SEL1, ++ 13, 1, 0, &ast1700_clk_lock); + -+/* Platform specific memory allocation */ -+void *pdu_malloc(unsigned long n) -+{ -+ return vmalloc(n); -+} ++ clks[AST1700_CLK_GATE_SDCLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "sdclk-gate"), ++ CREATE_CLK_NAME(id, "sdclk"), ++ 0, clk_base + AST1700_CLK_STOP, ++ 4, 0, &ast1700_clk_lock); + -+void pdu_free(void *p) -+{ -+ vfree(p); -+} ++ clks[AST1700_CLK_GATE_REFCLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "io-refclk-gate"), NULL, ++ CLK_IS_CRITICAL, clk_base + AST1700_CLK_STOP, ++ 6, 0, &ast1700_clk_lock); + -+/* 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; -+ } ++ clks[AST1700_CLK_GATE_LPCHCLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "lpchclk-gate"), NULL, ++ CLK_IS_CRITICAL, clk_base + AST1700_CLK_STOP, ++ 7, 0, &ast1700_clk_lock); + -+ /* -+ * 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); ++ clks[AST1700_CLK_GATE_MAC0CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "mac0clk-gate"), NULL, ++ 0, clk_base + AST1700_CLK_STOP, ++ 8, 0, &ast1700_clk_lock); + -+static int __init pdu_mod_init(void) -+{ -+ return 0; -+} ++ clks[AST1700_CLK_GATE_MAC1CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "mac1clk-gate"), NULL, ++ 0, clk_base + AST1700_CLK_STOP, ++ 9, 0, &ast1700_clk_lock); + -+static void __exit pdu_mod_exit(void) -+{ -+} ++ clks[AST1700_CLK_GATE_MAC2CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "mac2clk-gate"), NULL, ++ 0, clk_base + AST1700_CLK_STOP, ++ 10, 0, &ast1700_clk_lock); + -+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-04-08 18:03:46.629736033 +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. -+ */ ++ of_property_read_u32(ast1700_node, "uart-clk-source", &uart_clk_source); + -+#include -+#include -+#include -+#include -+#include -+#include ++ if (uart_clk_source) { ++ val = readl(clk_base + AST1700_CLK_SEL1) & ~GENMASK(12, 0); ++ uart_clk_source &= GENMASK(12, 0); ++ writel(val | uart_clk_source, clk_base + AST1700_CLK_SEL1); ++ } + -+#include "elppdu.h" ++ //UART0 ++ clks[AST1700_CLK_UART0] = ++ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart0clk"), ++ (id == 0) ? uartclk_sel0 : uartclk_sel1, ++ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), ++ 0, clk_base + AST1700_CLK_SEL1, ++ 0, 1, 0, &ast1700_clk_lock); + -+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) ")"); ++ clks[AST1700_CLK_GATE_UART0CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart0clk-gate"), ++ CREATE_CLK_NAME(id, "uart0clk"), ++ 0, clk_base + AST1700_CLK_STOP, ++ 11, 0, &ast1700_clk_lock); + -+// max of 16 devices -+#define MAX_DEV 16 ++ //UART1 ++ clks[AST1700_CLK_UART1] = ++ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart1clk"), ++ (id == 0) ? uartclk_sel0 : uartclk_sel1, ++ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), ++ 0, clk_base + AST1700_CLK_SEL1, ++ 1, 1, 0, &ast1700_clk_lock); + -+static struct platform_device *devices[MAX_DEV]; -+static int dev_id; ++ clks[AST1700_CLK_GATE_UART1CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart1clk-gate"), ++ CREATE_CLK_NAME(id, "uart1clk"), ++ 0, clk_base + AST1700_CLK_STOP, ++ 12, 0, &ast1700_clk_lock); + -+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, -+ }; ++ //UART2 ++ clks[AST1700_CLK_UART2] = ++ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart2clk"), ++ (id == 0) ? uartclk_sel0 : uartclk_sel1, ++ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), ++ 0, clk_base + AST1700_CLK_SEL1, ++ 2, 1, 0, &ast1700_clk_lock); + -+ if (dev_id >= MAX_DEV) { -+ pr_err("Too many devices; increase MAX_DEV.\n"); -+ return; -+ } ++ clks[AST1700_CLK_GATE_UART2CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart2clk-gate"), ++ CREATE_CLK_NAME(id, "uart2clk"), ++ 0, clk_base + AST1700_CLK_STOP, ++ 13, 0, &ast1700_clk_lock); + -+ 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); ++ //UART3 ++ clks[AST1700_CLK_UART3] = ++ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart3clk"), ++ (id == 0) ? uartclk_sel0 : uartclk_sel1, ++ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), ++ 0, clk_base + AST1700_CLK_SEL1, ++ 3, 1, 0, &ast1700_clk_lock); + -+ devices[dev_id] = NULL; -+ return; -+ } ++ clks[AST1700_CLK_GATE_UART3CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart3clk-gate"), ++ CREATE_CLK_NAME(id, "uart3clk"), ++ 0, clk_base + AST1700_CLK_STOP, ++ 14, 0, &ast1700_clk_lock); + -+ dev_id++; -+} ++ clks[AST1700_CLK_GATE_I3C0CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c0clk-gate"), ++ CREATE_CLK_NAME(id, "ahb"), ++ 0, clk_base + AST1700_CLK_STOP, ++ 16, 0, &ast1700_clk_lock); + -+static int __init get_irq_num(unsigned int irq_num) -+{ -+ if (IS_ENABLED(CONFIG_ARCH_ZYNQ)) { -+ struct of_phandle_args args = { 0 }; ++ clks[AST1700_CLK_GATE_I3C1CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c1clk-gate"), ++ CREATE_CLK_NAME(id, "ahb"), ++ 0, clk_base + AST1700_CLK_STOP, ++ 17, 0, &ast1700_clk_lock); + -+ /* -+ * 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. -+ */ ++ clks[AST1700_CLK_GATE_I3C2CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c2clk-gate"), ++ CREATE_CLK_NAME(id, "ahb"), ++ 0, clk_base + AST1700_CLK_STOP, ++ 18, 0, &ast1700_clk_lock); + -+ 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")); ++ clks[AST1700_CLK_GATE_I3C3CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c3clk-gate"), ++ CREATE_CLK_NAME(id, "ahb"), ++ 0, clk_base + AST1700_CLK_STOP, ++ 19, 0, &ast1700_clk_lock); + -+ if (irq_num < 32 || irq_num >= 96) { -+ pr_err("SPI interrupts must be in the range [32,96) on Zynq\n"); -+ return -EINVAL; -+ } ++ clks[AST1700_CLK_GATE_I3C4CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c4clk-gate"), ++ CREATE_CLK_NAME(id, "ahb"), ++ 0, clk_base + AST1700_CLK_STOP, ++ 20, 0, &ast1700_clk_lock); + -+ args.args_count = 3; -+ args.args[0] = 0; /* SPI */ -+ args.args[1] = irq_num - 32; -+ args.args[2] = 4; /* Active high, level-sensitive */ ++ clks[AST1700_CLK_GATE_I3C5CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c5clk-gate"), ++ CREATE_CLK_NAME(id, "ahb"), ++ 0, clk_base + AST1700_CLK_STOP, ++ 21, 0, &ast1700_clk_lock); + -+ irq_num = irq_create_of_mapping(&args); -+ of_node_put(args.np); -+ if (irq_num == 0) -+ return -EINVAL; -+ } ++ clks[AST1700_CLK_GATE_I3C6CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c6clk-gate"), ++ CREATE_CLK_NAME(id, "ahb"), ++ 0, clk_base + AST1700_CLK_STOP, ++ 22, 0, &ast1700_clk_lock); + -+ if (irq_num > INT_MAX) -+ return -EINVAL; ++ clks[AST1700_CLK_GATE_I3C7CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c7clk-gate"), ++ CREATE_CLK_NAME(id, "ahb"), ++ 0, clk_base + AST1700_CLK_STOP, ++ 23, 0, &ast1700_clk_lock); + -+ return irq_num; -+} ++ clks[AST1700_CLK_GATE_I3C8CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c8clk-gate"), ++ CREATE_CLK_NAME(id, "ahb"), ++ 0, clk_base + AST1700_CLK_STOP, ++ 24, 0, &ast1700_clk_lock); + -+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 ++ clks[AST1700_CLK_GATE_I3C9CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c9clk-gate"), ++ CREATE_CLK_NAME(id, "ahb"), ++ 0, clk_base + AST1700_CLK_STOP, ++ 25, 0, &ast1700_clk_lock); + -+ 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); -+ } ++ clks[AST1700_CLK_GATE_I3C10CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c10clk-gate"), ++ CREATE_CLK_NAME(id, "ahb"), ++ 0, clk_base + AST1700_CLK_STOP, ++ 26, 0, &ast1700_clk_lock); + -+#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 ++ clks[AST1700_CLK_GATE_I3C11CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c11clk-gate"), ++ CREATE_CLK_NAME(id, "ahb"), ++ 0, clk_base + AST1700_CLK_STOP, ++ 27, 0, &ast1700_clk_lock); + -+#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 ++ clks[AST1700_CLK_GATE_I3C12CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c12clk-gate"), ++ CREATE_CLK_NAME(id, "ahb"), ++ 0, clk_base + AST1700_CLK_STOP, ++ 28, 0, &ast1700_clk_lock); + -+ return 0; -+} -+module_init(pdu_vex_mod_init); ++ clks[AST1700_CLK_GATE_I3C13CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c13clk-gate"), ++ CREATE_CLK_NAME(id, "ahb"), ++ 0, clk_base + AST1700_CLK_STOP, ++ 29, 0, &ast1700_clk_lock); + -+static void __exit pdu_vex_mod_exit(void) -+{ -+ int i; ++ clks[AST1700_CLK_GATE_I3C14CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c14clk-gate"), ++ CREATE_CLK_NAME(id, "ahb"), ++ 0, clk_base + AST1700_CLK_STOP, ++ 30, 0, &ast1700_clk_lock); + -+ for (i = 0; i < MAX_DEV; i++) -+ platform_device_unregister(devices[i]); -+} -+module_exit(pdu_vex_mod_exit); ++ clks[AST1700_CLK_GATE_I3C15CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c15clk-gate"), ++ CREATE_CLK_NAME(id, "ahb"), ++ 0, clk_base + AST1700_CLK_STOP, ++ 31, 0, &ast1700_clk_lock); + -+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-04-08 18:03:46.629736033 +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. -+ */ ++ /*clk stop 2 */ ++ //UART5 ++ clks[AST1700_CLK_UART5] = ++ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart5clk"), ++ (id == 0) ? uartclk_sel0 : uartclk_sel1, ++ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), ++ 0, clk_base + AST1700_CLK_SEL1, ++ 5, 1, 0, &ast1700_clk_lock); + -+#ifndef NISTTRNG_H -+#define NISTTRNG_H ++ clks[AST1700_CLK_GATE_UART5CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart5clk-gate"), ++ CREATE_CLK_NAME(id, "uart5clk"), ++ 0, clk_base + AST1700_CLK_STOP2, ++ 0, 0, &ast1700_clk_lock); + -+#include "synversion.h" -+#include "elppdu.h" -+#include "nisttrng_hw.h" -+#include "nisttrng_common.h" -+#include "nisttrng_private.h" ++ //UART6 ++ clks[AST1700_CLK_UART6] = ++ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart6clk"), ++ (id == 0) ? uartclk_sel0 : uartclk_sel1, ++ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), ++ 0, clk_base + AST1700_CLK_SEL1, ++ 6, 1, 0, &ast1700_clk_lock); + -+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-04-08 18:03:46.629736033 +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. -+// -+// ------------------------------------------------------------------------ ++ clks[AST1700_CLK_GATE_UART6CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart6clk-gate"), ++ CREATE_CLK_NAME(id, "uart6clk"), ++ 0, clk_base + AST1700_CLK_STOP2, ++ 1, 0, &ast1700_clk_lock); + -+#ifndef NISTTRNG_COMMON_H -+#define NISTTRNG_COMMON_H ++ //UART7 ++ clks[AST1700_CLK_UART7] = ++ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart7clk"), ++ (id == 0) ? uartclk_sel0 : uartclk_sel1, ++ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), ++ 0, clk_base + AST1700_CLK_SEL1, ++ 7, 1, 0, &ast1700_clk_lock); + -+#define NIST_TRNG_RETRY_MAX 5000000UL ++ clks[AST1700_CLK_GATE_UART7CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart7clk-gate"), ++ CREATE_CLK_NAME(id, "uart7clk"), ++ 0, clk_base + AST1700_CLK_STOP2, ++ 2, 0, &ast1700_clk_lock); + -+#define NIST_DFLT_MAX_BITS_PER_REQ BIT(19) -+#define NIST_DFLT_MAX_REQ_PER_SEED BIT(48) ++ //UART8 ++ clks[AST1700_CLK_UART8] = ++ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart8clk"), ++ (id == 0) ? uartclk_sel0 : uartclk_sel1, ++ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), ++ 0, clk_base + AST1700_CLK_SEL1, ++ 8, 1, 0, &ast1700_clk_lock); + -+/* Do not change the following parameters */ -+#define NIST_TRNG_DFLT_MAX_REJECTS 10 ++ clks[AST1700_CLK_GATE_UART8CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart8clk-gate"), ++ CREATE_CLK_NAME(id, "uart8clk"), ++ 0, clk_base + AST1700_CLK_STOP2, ++ 3, 0, &ast1700_clk_lock); + -+#define DEBUG(...) -+//#define DEBUG(...) printk(__VA_ARGS__) ++ //UART9 ++ clks[AST1700_CLK_UART9] = ++ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart9clk"), ++ (id == 0) ? uartclk_sel0 : uartclk_sel1, ++ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), ++ 0, clk_base + AST1700_CLK_SEL1, ++ 9, 1, 0, &ast1700_clk_lock); + -+enum nisttrng_sec_strength { -+ SEC_STRNT_AES128 = 0, -+ SEC_STRNT_AES256 = 1 -+}; ++ clks[AST1700_CLK_GATE_UART9CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart9clk-gate"), ++ CREATE_CLK_NAME(id, "uart9clk"), ++ 0, clk_base + AST1700_CLK_STOP2, ++ 4, 0, &ast1700_clk_lock); + -+enum nisttrng_drbg_arch { -+ AES128 = 0, -+ AES256 = 1 -+}; ++ //UART10 ++ clks[AST1700_CLK_UART10] = ++ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart10clk"), ++ (id == 0) ? uartclk_sel0 : uartclk_sel1, ++ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), ++ 0, clk_base + AST1700_CLK_SEL1, ++ 10, 1, 0, &ast1700_clk_lock); + -+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 -+}; ++ clks[AST1700_CLK_GATE_UART10CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart10clk-gate"), ++ CREATE_CLK_NAME(id, "uart10clk"), ++ 0, clk_base + AST1700_CLK_STOP2, ++ 5, 0, &ast1700_clk_lock); + -+struct nist_trng_state { -+ u32 *base; ++ //UART11 ++ clks[AST1700_CLK_UART11] = ++ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart11clk"), ++ (id == 0) ? uartclk_sel0 : uartclk_sel1, ++ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), ++ 0, clk_base + AST1700_CLK_SEL1, ++ 11, 1, 0, &ast1700_clk_lock); + -+ /* 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; ++ clks[AST1700_CLK_GATE_UART11CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart11clk-gate"), ++ CREATE_CLK_NAME(id, "uart11clk"), ++ 0, clk_base + AST1700_CLK_STOP2, ++ 6, 0, &ast1700_clk_lock); + -+ struct { -+ unsigned int ext_enum, -+ ext_ver, -+ rel_num; -+ } corekit_rel; ++ //uart12: call bmc uart ++ clks[AST1700_CLK_UART12] = ++ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart12clk"), ++ (id == 0) ? uartclk_sel0 : uartclk_sel1, ++ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), ++ 0, clk_base + AST1700_CLK_SEL1, ++ 12, 1, 0, &ast1700_clk_lock); + -+ struct { -+ unsigned int core_type, -+ bg8, -+ cdc_synch_depth, -+ background_noise, -+ edu_present, -+ aes_datapath, -+ aes_max_key_size, -+ personilzation_str; -+ } build_cfg0; ++ clks[AST1700_CLK_GATE_UART12CLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart12clk-gate"), ++ CREATE_CLK_NAME(id, "uart12clk"), ++ 0, clk_base + AST1700_CLK_STOP2, ++ 7, 0, &ast1700_clk_lock); + -+ 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; ++ clks[AST1700_CLK_GATE_FSICLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "fsiclk-gate"), NULL, ++ 0, clk_base + AST1700_CLK_STOP2, ++ 8, 0, &ast1700_clk_lock); + -+ 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; ++ clks[AST1700_CLK_GATE_LTPIPHYCLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "ltpiphyclk-gate"), NULL, ++ CLK_IS_CRITICAL, clk_base + AST1700_CLK_STOP2, ++ 9, 0, &ast1700_clk_lock); + -+ /* 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; ++ clks[AST1700_CLK_GATE_LTPICLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "ltpiclk-gate"), NULL, ++ CLK_IS_CRITICAL, clk_base + AST1700_CLK_STOP2, ++ 10, 0, &ast1700_clk_lock); + -+ /* 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; -+}; ++ clks[AST1700_CLK_GATE_VGALCLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "vgalclk-gate"), NULL, ++ 0, clk_base + AST1700_CLK_STOP2, ++ 11, 0, &ast1700_clk_lock); + -+#define nist_trng_zero_status(x) \ -+ memset(&((x)->status), 0, sizeof((x)->status)) ++ clks[AST1700_CLK_GATE_USBUARTCLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "usbuartclk-gate"), NULL, ++ 0, clk_base + AST1700_CLK_STOP2, ++ 12, 0, &ast1700_clk_lock); + -+#define DRBG_INSTANTIATED(cs) \ -+ ((((cs) == NIST_TRNG_STATE_INSTANTIATE) || \ -+ ((cs) == NIST_TRNG_STATE_RESEED) || \ -+ ((cs) == NIST_TRNG_STATE_GENERATE)) ? 1 : 0) ++ clk_hw_register_fixed_factor(NULL, CREATE_CLK_NAME(id, "canclk"), CREATE_CLK_NAME(id, "apll"), 0, 1, 10); + -+#define REQ_SEC_STRENGTH_IS_VALID(sec_st) \ -+ ((((sec_st) > 0) && ((sec_st) <= 256)) ? 1 : 0) ++ clks[AST1700_CLK_GATE_CANCLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "canclk-gate"), ++ CREATE_CLK_NAME(id, "canclk"), ++ 0, clk_base + AST1700_CLK_STOP2, ++ 13, 0, &ast1700_clk_lock); + -+#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-04-08 18:03:46.629736033 +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. -+ */ ++ clks[AST1700_CLK_GATE_PCICLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "pciclk-gate"), NULL, ++ 0, clk_base + AST1700_CLK_STOP2, ++ 14, 0, &ast1700_clk_lock); + -+#ifndef NISTTRNG_HW_H -+#define NISTTRNG_HW_H ++ clks[AST1700_CLK_GATE_SLICLK] = ++ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "sliclk-gate"), NULL, ++ 0, clk_base + AST1700_CLK_STOP2, ++ 15, 0, &ast1700_clk_lock); + -+/* HW related Parameters */ -+#define NIST_TRNG_RAND_BLK_SIZE_BITS 128 -+#define CHX_URUN_BLANK_AFTER_RESET 0x3 ++ of_clk_add_hw_provider(ast1700_node, of_clk_hw_onecell_get, clk_data); + -+/* 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 ++ return 0; ++}; + -+/* 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 ++CLK_OF_DECLARE_DRIVER(ast1700, "aspeed,ast1700-scu", AST1700_clk_init); + -+/* 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 +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 +@@ -19,7 +19,7 @@ + * This includes the gates (configured from aspeed_g6_gates), plus the + * explicitly-configured clocks (ASPEED_CLK_HPLL and up). + */ +-#define ASPEED_G6_NUM_CLKS 73 ++#define ASPEED_G6_NUM_CLKS 76 + + #define ASPEED_G6_SILICON_REV 0x014 + #define CHIP_REVISION_ID GENMASK(23, 16) +@@ -59,8 +59,24 @@ + + #define ASPEED_G6_STRAP1 0x500 + ++#define ASPEED_UARTCLK_FROM_UXCLK 0x338 + -+#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 ASPEED_MAC12_CLK_DLY 0x340 ++#define ASPEED_MAC12_CLK_DLY_100M 0x348 ++#define ASPEED_MAC12_CLK_DLY_10M 0x34C + -+#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))) + #define ASPEED_MAC34_CLK_DLY 0x350 ++#define ASPEED_MAC34_CLK_DLY_100M 0x358 ++#define ASPEED_MAC34_CLK_DLY_10M 0x35C + -+/* 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 ++#define ASPEED_G6_MAC34_DRIVING_CTRL 0x458 + -+/* 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 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 @@ + /* AST2600 revision: A0, A1, A2, etc */ + static u8 soc_rev; + ++struct mac_delay_config { ++ u32 tx_delay_1000; ++ u32 rx_delay_1000; ++ u32 tx_delay_100; ++ u32 rx_delay_100; ++ u32 tx_delay_10; ++ u32 rx_delay_10; ++}; + -+#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))) ++union mac_delay_1g { ++ u32 w; ++ struct { ++ unsigned int tx_delay_1 : 6; /* bit[5:0] */ ++ unsigned int tx_delay_2 : 6; /* bit[11:6] */ ++ unsigned int rx_delay_1 : 6; /* bit[17:12] */ ++ unsigned int rx_delay_2 : 6; /* bit[23:18] */ ++ unsigned int rx_clk_inv_1 : 1; /* bit[24] */ ++ unsigned int rx_clk_inv_2 : 1; /* bit[25] */ ++ unsigned int rmii_tx_data_at_falling_1 : 1; /* bit[26] */ ++ unsigned int rmii_tx_data_at_falling_2 : 1; /* bit[27] */ ++ unsigned int rgmiick_pad_dir : 1; /* bit[28] */ ++ unsigned int rmii_50m_oe_1 : 1; /* bit[29] */ ++ unsigned int rmii_50m_oe_2 : 1; /* bit[30] */ ++ unsigned int rgmii_125m_o_sel : 1; /* bit[31] */ ++ } b; ++}; + -+/* 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 ++union mac_delay_100_10 { ++ u32 w; ++ struct { ++ unsigned int tx_delay_1 : 6; /* bit[5:0] */ ++ unsigned int tx_delay_2 : 6; /* bit[11:6] */ ++ unsigned int rx_delay_1 : 6; /* bit[17:12] */ ++ unsigned int rx_delay_2 : 6; /* bit[23:18] */ ++ unsigned int rx_clk_inv_1 : 1; /* bit[24] */ ++ unsigned int rx_clk_inv_2 : 1; /* bit[25] */ ++ unsigned int reserved_0 : 6; /* bit[31:26] */ ++ } b; ++}; + /* + * 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 @@ + * ref0 and ref1 are essential for the SoC to operate + * mpll is required if SDRAM is used + */ +-static const struct aspeed_gate_data aspeed_g6_gates[] = { ++static struct aspeed_gate_data aspeed_g6_gates[] = { + /* clk rst name parent flags */ + [ASPEED_CLK_GATE_MCLK] = { 0, -1, "mclk-gate", "mpll", CLK_IS_CRITICAL }, /* SDRAM */ + [ASPEED_CLK_GATE_ECLK] = { 1, 6, "eclk-gate", "eclk", 0 }, /* Video Engine */ + [ASPEED_CLK_GATE_GCLK] = { 2, 7, "gclk-gate", NULL, 0 }, /* 2D engine */ + /* vclk parent - dclk/d1clk/hclk/mclk */ + [ASPEED_CLK_GATE_VCLK] = { 3, -1, "vclk-gate", NULL, 0 }, /* Video Capture */ +- [ASPEED_CLK_GATE_BCLK] = { 4, 8, "bclk-gate", "bclk", 0 }, /* PCIe/PCI */ ++ [ASPEED_CLK_GATE_BCLK] = { 4, 8, "bclk-gate", "bclk", CLK_IS_CRITICAL }, /* PCIe/PCI */ + /* 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 @@ + /* Reserved 26 */ + [ASPEED_CLK_GATE_EMMCCLK] = { 27, 16, "emmcclk-gate", NULL, 0 }, /* For card clk */ + /* Reserved 28/29/30 */ +- [ASPEED_CLK_GATE_LCLK] = { 32, 32, "lclk-gate", NULL, 0 }, /* LPC */ +- [ASPEED_CLK_GATE_ESPICLK] = { 33, -1, "espiclk-gate", NULL, 0 }, /* eSPI */ ++ [ASPEED_CLK_GATE_LCLK] = { 32, 32, "lclk-gate", NULL, CLK_IS_CRITICAL }, /* LPC */ ++ [ASPEED_CLK_GATE_ESPICLK] = { 33, -1, "espiclk-gate", NULL, CLK_IS_CRITICAL }, /* eSPI */ + [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 @@ + [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 */ +- [ASPEED_CLK_GATE_UART1CLK] = { 48, -1, "uart1clk-gate", "uart", 0 }, /* UART1 */ +- [ASPEED_CLK_GATE_UART2CLK] = { 49, -1, "uart2clk-gate", "uart", 0 }, /* UART2 */ +- [ASPEED_CLK_GATE_UART3CLK] = { 50, -1, "uart3clk-gate", "uart", 0 }, /* UART3 */ +- [ASPEED_CLK_GATE_UART4CLK] = { 51, -1, "uart4clk-gate", "uart", 0 }, /* UART4 */ ++ [ASPEED_CLK_GATE_UART1CLK] = { 48, -1, "uart1clk-gate", "uxclk", CLK_IS_CRITICAL }, /* UART1 */ ++ [ASPEED_CLK_GATE_UART2CLK] = { 49, -1, "uart2clk-gate", "uxclk", CLK_IS_CRITICAL }, /* UART2 */ ++ [ASPEED_CLK_GATE_UART3CLK] = { 50, -1, "uart3clk-gate", "uxclk", 0 }, /* UART3 */ ++ [ASPEED_CLK_GATE_UART4CLK] = { 51, -1, "uart4clk-gate", "uxclk", 0 }, /* UART4 */ + [ASPEED_CLK_GATE_MAC3CLK] = { 52, 52, "mac3clk-gate", "mac34", 0 }, /* MAC3 */ + [ASPEED_CLK_GATE_MAC4CLK] = { 53, 53, "mac4clk-gate", "mac34", 0 }, /* MAC4 */ +- [ASPEED_CLK_GATE_UART6CLK] = { 54, -1, "uart6clk-gate", "uartx", 0 }, /* UART6 */ +- [ASPEED_CLK_GATE_UART7CLK] = { 55, -1, "uart7clk-gate", "uartx", 0 }, /* UART7 */ +- [ASPEED_CLK_GATE_UART8CLK] = { 56, -1, "uart8clk-gate", "uartx", 0 }, /* UART8 */ +- [ASPEED_CLK_GATE_UART9CLK] = { 57, -1, "uart9clk-gate", "uartx", 0 }, /* UART9 */ +- [ASPEED_CLK_GATE_UART10CLK] = { 58, -1, "uart10clk-gate", "uartx", 0 }, /* UART10 */ +- [ASPEED_CLK_GATE_UART11CLK] = { 59, -1, "uart11clk-gate", "uartx", 0 }, /* UART11 */ +- [ASPEED_CLK_GATE_UART12CLK] = { 60, -1, "uart12clk-gate", "uartx", 0 }, /* UART12 */ +- [ASPEED_CLK_GATE_UART13CLK] = { 61, -1, "uart13clk-gate", "uartx", 0 }, /* UART13 */ ++ [ASPEED_CLK_GATE_UART6CLK] = { 54, -1, "uart6clk-gate", "uxclk", 0 }, /* UART6 */ ++ [ASPEED_CLK_GATE_UART7CLK] = { 55, -1, "uart7clk-gate", "uxclk", 0 }, /* UART7 */ ++ [ASPEED_CLK_GATE_UART8CLK] = { 56, -1, "uart8clk-gate", "uxclk", 0 }, /* UART8 */ ++ [ASPEED_CLK_GATE_UART9CLK] = { 57, -1, "uart9clk-gate", "uxclk", 0 }, /* UART9 */ ++ [ASPEED_CLK_GATE_UART10CLK] = { 58, -1, "uart10clk-gate", "uxclk", 0 }, /* UART10 */ ++ [ASPEED_CLK_GATE_UART11CLK] = { 59, -1, "uart11clk-gate", "uxclk", CLK_IS_CRITICAL }, /* UART11 */ ++ [ASPEED_CLK_GATE_UART12CLK] = { 60, -1, "uart12clk-gate", "uxclk", 0 }, /* UART12 */ ++ [ASPEED_CLK_GATE_UART13CLK] = { 61, -1, "uart13clk-gate", "uxclk", 0 }, /* UART13 */ + [ASPEED_CLK_GATE_FSICLK] = { 62, 59, "fsiclk-gate", "fsiclk", 0 }, /* FSI */ + }; + +@@ -184,6 +239,18 @@ + { 0 } + }; + ++static const struct clk_div_table ast2600_sd_div_table[] = { ++ { 0x0, 2 }, ++ { 0x1, 4 }, ++ { 0x2, 6 }, ++ { 0x3, 8 }, ++ { 0x4, 10 }, ++ { 0x5, 12 }, ++ { 0x6, 14 }, ++ { 0x7, 1 }, ++ { 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) + static const struct clk_div_table ast2600_mac_div_table[] = { + { 0x0, 4 }, + { 0x1, 4 }, +@@ -384,9 +451,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; ++ u32 val; ++ int ret; + + /* Use set to clear register */ +- return regmap_write(ar->map, reg + 0x04, rst); ++ ret = regmap_write(ar->map, reg + 0x04, rst); ++ /* Add dummy read to ensure the write transfer is finished */ ++ regmap_read(ar->map, reg + 4, &val); ++ return ret; + } + + static int aspeed_g6_reset_assert(struct reset_controller_dev *rcdev, +@@ -458,11 +530,6 @@ + return hw; + } + +-static const char *const emmc_extclk_parent_names[] = { +- "emmc_extclk_hpll_in", +- "mpll", +-}; +- + static const char * const vclk_parent_names[] = { + "dpll", + "d1pll", +@@ -484,7 +551,7 @@ + struct aspeed_reset *ar; + struct regmap *map; + struct clk_hw *hw; +- u32 val, rate; ++ u32 val; + int i, ret; + + map = syscon_node_to_regmap(dev->of_node); +@@ -510,70 +577,50 @@ + return ret; + } + +- /* UART clock div13 setting */ +- regmap_read(map, ASPEED_G6_MISC_CTRL, &val); +- if (val & UART_DIV13_EN) +- rate = 24000000 / 13; +- else +- rate = 24000000; +- hw = clk_hw_register_fixed_rate(dev, "uart", NULL, 0, rate); +- if (IS_ERR(hw)) +- return PTR_ERR(hw); +- aspeed_g6_clk_data->hws[ASPEED_CLK_UART] = hw; +- +- /* UART6~13 clock div13 setting */ +- regmap_read(map, 0x80, &val); +- if (val & BIT(31)) +- rate = 24000000 / 13; +- else +- rate = 24000000; +- hw = clk_hw_register_fixed_rate(dev, "uartx", NULL, 0, rate); +- if (IS_ERR(hw)) +- return PTR_ERR(hw); +- aspeed_g6_clk_data->hws[ASPEED_CLK_UARTX] = hw; +- +- /* 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); +- +- hw = clk_hw_register_mux(dev, "emmc_extclk_mux", +- emmc_extclk_parent_names, +- ARRAY_SIZE(emmc_extclk_parent_names), 0, +- scu_g6_base + ASPEED_G6_CLK_SELECTION1, 11, 1, +- 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); + +- hw = clk_hw_register_divider_table(dev, "emmc_extclk", +- "emmc_extclk_gate", 0, +- scu_g6_base + +- ASPEED_G6_CLK_SELECTION1, 12, +- 3, 0, ast2600_emmc_extclk_div_table, ++ //ast2600 emmc clk should under 200Mhz ++ hw = clk_hw_register_divider_table(dev, "emmc_extclk", "emmc_extclk_gate", 0, ++ scu_g6_base + ASPEED_G6_CLK_SELECTION1, 12, 3, 0, ++ ast2600_emmc_extclk_div_table, + &aspeed_g6_clk_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_g6_clk_data->hws[ASPEED_CLK_EMMC] = hw; + +- /* SD/SDIO clock divider and gate */ +- hw = clk_hw_register_gate(dev, "sd_extclk_gate", "hpll", 0, +- scu_g6_base + ASPEED_G6_CLK_SELECTION4, 31, 0, +- &aspeed_g6_clk_lock); +- if (IS_ERR(hw)) +- return PTR_ERR(hw); ++ clk_hw_register_fixed_rate(NULL, "hclk", NULL, 0, 200000000); + -+/*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 ++ regmap_read(map, 0x310, &val); ++ if (val & BIT(8)) { ++ /* SD/SDIO clock divider and gate */ ++ hw = clk_hw_register_gate(dev, "sd_extclk_gate", "apll", 0, ++ scu_g6_base + ASPEED_G6_CLK_SELECTION4, 31, 0, ++ &aspeed_g6_clk_lock); ++ if (IS_ERR(hw)) ++ return PTR_ERR(hw); ++ } else { ++ /* SD/SDIO clock divider and gate */ ++ hw = clk_hw_register_gate(dev, "sd_extclk_gate", "hclk", 0, ++ scu_g6_base + ASPEED_G6_CLK_SELECTION4, 31, 0, ++ &aspeed_g6_clk_lock); ++ if (IS_ERR(hw)) ++ return PTR_ERR(hw); ++ } + -+#define _NIST_TRNG_EDU_RBC_CTRL_CH_RATE_MASK 0xFUL -+#define _NIST_TRNG_EDU_RBC_CTRL_CH_URUN_BLANK_MASK 0x3UL + hw = clk_hw_register_divider_table(dev, "sd_extclk", "sd_extclk_gate", +- 0, scu_g6_base + ASPEED_G6_CLK_SELECTION4, 28, 3, 0, +- ast2600_div_table, +- &aspeed_g6_clk_lock); ++ 0, scu_g6_base + ASPEED_G6_CLK_SELECTION4, 28, 3, 0, ++ ast2600_sd_div_table, ++ &aspeed_g6_clk_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + -+#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))) + aspeed_g6_clk_data->hws[ASPEED_CLK_SDIO] = hw; + + /* MAC1/2 RMII 50MHz RCLK */ +@@ -645,8 +692,8 @@ + return PTR_ERR(hw); + aspeed_g6_clk_data->hws[ASPEED_CLK_LHCLK] = hw; + +- /* gfx d1clk : use dp clk */ +- regmap_update_bits(map, ASPEED_G6_CLK_SELECTION1, GENMASK(10, 8), BIT(10)); ++ /* gfx d1clk : use usb phy */ ++ regmap_update_bits(map, ASPEED_G6_CLK_SELECTION1, GENMASK(10, 8), BIT(9)); + /* SoC Display clock selection */ + hw = clk_hw_register_mux(dev, "d1clk", d1clk_parent_names, + ARRAY_SIZE(d1clk_parent_names), 0, +@@ -677,6 +724,8 @@ + return PTR_ERR(hw); + aspeed_g6_clk_data->hws[ASPEED_CLK_VCLK] = hw; + ++ //vclk : force disable dynmamic slow down and fix vclk = eclk / 2 ++ regmap_update_bits(map, ASPEED_G6_CLK_SELECTION1, GENMASK(31, 28), 0); + /* 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 @@ + return PTR_ERR(hw); + aspeed_g6_clk_data->hws[ASPEED_CLK_ECLK] = hw; + ++ /* uartx parent assign*/ ++ for (i = 0; i < 13; i++) { ++ if (i < 6 && i != 4) { ++ regmap_read(map, 0x310, &val); ++ if (val & BIT(i)) ++ aspeed_g6_gates[ASPEED_CLK_GATE_UART1CLK + i].parent_name = "huxclk"; ++ else ++ aspeed_g6_gates[ASPEED_CLK_GATE_UART1CLK + i].parent_name = "uxclk"; ++ } ++ if (i == 4) ++ aspeed_g6_gates[ASPEED_CLK_GATE_UART1CLK + i].parent_name = "uart5"; ++ if (i > 5 && i != 4) { ++ regmap_read(map, 0x314, &val); ++ if (val & BIT(i)) ++ aspeed_g6_gates[ASPEED_CLK_GATE_UART1CLK + i].parent_name = "huxclk"; ++ else ++ aspeed_g6_gates[ASPEED_CLK_GATE_UART1CLK + i].parent_name = "uxclk"; ++ } ++ } + -+#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))) + 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 @@ + static void __init aspeed_g6_cc(struct regmap *map) + { + struct clk_hw *hw; +- u32 val, div, divbits, axi_div, ahb_div; ++ u32 val, freq, div, divbits, axi_div, ahb_div; ++ u32 mult; + + clk_hw_register_fixed_rate(NULL, "clkin", NULL, 0, 25000000); + +@@ -814,6 +884,55 @@ + hw = clk_hw_register_fixed_rate(NULL, "usb-phy-40m", NULL, 0, 40000000); + aspeed_g6_clk_data->hws[ASPEED_CLK_USBPHY_40M] = hw; + ++ /* uart5 clock selection */ ++ regmap_read(map, ASPEED_G6_MISC_CTRL, &val); ++ if (val & UART_DIV13_EN) ++ div = 13; ++ else ++ div = 1; ++ regmap_read(map, ASPEED_G6_CLK_SELECTION2, &val); ++ if (val & BIT(14)) ++ freq = 192000000; ++ else ++ freq = 24000000; ++ freq = freq / div; + -+#define NISTTRNG_EDU_RBC_CTRL_GET_CH_RATE_AFTER_RESET 0x0 -+#define NISTTRNG_EDU_RBC_CTRL_SET_CH_URUN_BLANK_AFTER_RESET 0x3 ++ aspeed_g6_clk_data->hws[ASPEED_CLK_UART5] = clk_hw_register_fixed_rate(NULL, "uart5", NULL, 0, freq); + -+/* 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 ++ /* UART1~13 clock div13 setting except uart5 */ ++ regmap_read(map, ASPEED_G6_CLK_SELECTION5, &val); + -+#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) ++ switch (val & 0x3) { ++ case 0: ++ aspeed_g6_clk_data->hws[ASPEED_CLK_UARTX] = clk_hw_register_fixed_factor(NULL, "uartx", "apll", 0, 1, 4); ++ break; ++ case 1: ++ aspeed_g6_clk_data->hws[ASPEED_CLK_UARTX] = clk_hw_register_fixed_factor(NULL, "uartx", "apll", 0, 1, 2); ++ break; ++ case 2: ++ aspeed_g6_clk_data->hws[ASPEED_CLK_UARTX] = clk_hw_register_fixed_factor(NULL, "uartx", "apll", 0, 1, 1); ++ break; ++ case 3: ++ aspeed_g6_clk_data->hws[ASPEED_CLK_UARTX] = clk_hw_register_fixed_factor(NULL, "uartx", "ahb", 0, 1, 1); ++ break; ++ } + -+/* 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 ++ /* uxclk */ ++ regmap_read(map, ASPEED_UARTCLK_FROM_UXCLK, &val); ++ div = ((val >> 8) & 0x3ff) * 2; ++ mult = val & 0xff; + -+#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) ++ hw = clk_hw_register_fixed_factor(NULL, "uxclk", "uartx", 0, mult, div); ++ aspeed_g6_clk_data->hws[ASPEED_CLK_UXCLK] = hw; + -+/* 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 ++ /* huxclk */ ++ regmap_read(map, 0x33c, &val); ++ div = ((val >> 8) & 0x3ff) * 2; ++ mult = val & 0xff; + -+#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) ++ hw = clk_hw_register_fixed_factor(NULL, "huxclk", "uartx", 0, mult, div); ++ aspeed_g6_clk_data->hws[ASPEED_CLK_HUXCLK] = hw; + -+/*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) + /* 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 @@ + 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 @@ + return; + } + ++ of_property_read_u32(np, "uart-clk-source", &uart_clk_source); + -+/* 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 ++ if (uart_clk_source) { ++ if (uart_clk_source & GENMASK(5, 0)) ++ regmap_update_bits(map, ASPEED_G6_CLK_SELECTION4, GENMASK(5, 0), uart_clk_source & GENMASK(5, 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) ++ if (uart_clk_source & GENMASK(12, 6)) ++ regmap_update_bits(map, ASPEED_G6_CLK_SELECTION5, GENMASK(12, 6), uart_clk_source & GENMASK(12, 6)); ++ } + -+/*EDU_ISTAT*/ ++ /* fixed settings for RGMII/RMII clock generator */ ++ /* MAC1/2 RGMII 125MHz = EPLL / 8 */ ++ regmap_update_bits(map, ASPEED_G6_CLK_SELECTION2, GENMASK(23, 20), ++ (0x7 << 20)); + -+#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 ++ /* MAC3/4 RMII 50MHz = HCLK / 4 */ ++ regmap_update_bits(map, ASPEED_G6_CLK_SELECTION4, GENMASK(18, 16), ++ (0x3 << 16)); + -+#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) ++ /* 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); + -+/* 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 ++ /* 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); + -+/* 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) ++ /* MAC3/4 default pad driving strength */ ++ regmap_write(map, ASPEED_G6_MAC34_DRIVING_CTRL, 0x0000000f); + -+// 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) ++ 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); + -+/* 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) ++ 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); + -+/* 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) ++ /* 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)); + -+/* 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) + aspeed_g6_cc(map); + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, aspeed_g6_clk_data); + 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 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2024 ASPEED Technology Inc. ++ * Author: Ryan Chen ++ */ ++#include ++#include ++#include ++#include ++#include ++#include + -+/* 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) ++#include ++#include + -+#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 REVISION_ID GENMASK(23, 16) + -+#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) ++/* SOC0 */ ++#define SCU0_HWSTRAP1 0x010 ++#define SCU0_CLK_STOP 0x240 ++#define SCU0_CLK_SEL1 0x280 ++#define SCU0_CLK_SEL2 0x284 ++#define GET_USB_REFCLK_DIV(x) ((GENMASK(23, 20) & (x)) >> 20) ++#define UART_DIV13_EN BIT(30) ++#define SCU0_HPLL_PARAM 0x300 ++#define SCU0_DPLL_PARAM 0x308 ++#define SCU0_MPLL_PARAM 0x310 ++#define SCU0_D0CLK_PARAM 0x320 ++#define SCU0_D1CLK_PARAM 0x330 ++#define SCU0_CRT0CLK_PARAM 0x340 ++#define SCU0_CRT1CLK_PARAM 0x350 ++#define SCU0_MPHYCLK_PARAM 0x360 + -+#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) ++/* SOC1 */ ++#define SCU1_CLK_STOP 0x240 ++#define AST2755_SCU1_CLK_STOP 0x248 ++#define SCU1_CLK_STOP2 0x260 ++#define SCU1_CLK_SEL1 0x280 ++#define SCU1_CLK_SEL2 0x284 ++#define SCU1_CLK_I3C_DIV_MASK GENMASK(25, 23) ++#define SCU1_CLK_I3C_DIV(n) ((n) - 1) ++#define UXCLK_MASK GENMASK(1, 0) ++#define HUXCLK_MASK GENMASK(4, 3) ++#define SCU1_HPLL_PARAM 0x300 ++#define SCU1_APLL_PARAM 0x310 ++#define SCU1_DPLL_PARAM 0x320 ++#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 + -+#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-04-08 18:03:46.629736033 +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. ++ * 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 + -+#ifndef NISTTRNG_PRIVATE_H -+#define NISTTRNG_PRIVATE_H -+ -+#include "elppdu.h" -+#include "nisttrng_hw.h" -+#include "nisttrng_common.h" ++struct mac_delay_config { ++ u32 tx_delay_1000; ++ u32 rx_delay_1000; ++ u32 tx_delay_100; ++ u32 rx_delay_100; ++ u32 tx_delay_10; ++ u32 rx_delay_10; ++}; + -+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); ++enum ast2700_clk_type { ++ CLK_MUX, ++ CLK_PLL, ++ CLK_HPLL, ++ CLK_GATE, ++ CLK_MISC, ++ CLK_FIXED, ++ CLK_FIXED_DISPLAY, ++ CLK_DIVIDER, ++ CLK_UART_PLL, ++ CLK_FIXED_FACTOR, ++ CLK_GATE_ASPEED, ++}; + -+/* ---------- 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); ++struct ast2700_clk_fixed_factor_data { ++ unsigned int mult; ++ unsigned int div; ++ int parent_id; ++}; + -+/* ---------- 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); ++struct ast2700_clk_gate_data { ++ int parent_id; ++ u32 flags; ++ u32 reg; ++ u8 bit; ++}; + -+/* ---------- Load data APIs ---------- */ -+int nisttrng_load_ps_addin(struct nist_trng_state *state, void *input_str); ++struct ast2700_clk_mux_data { ++ const struct clk_hw **parent_hws; ++ const unsigned int *parent_ids; ++ unsigned int num_parents; ++ u8 bit_shift; ++ u8 bit_width; ++ u32 reg; ++}; + -+/* ---------- 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); ++struct ast2700_clk_div_data { ++ const struct clk_div_table *div_table; ++ unsigned int parent_id; ++ u8 bit_shift; ++ u8 bit_width; ++ u32 reg; ++}; + -+/* ---------- edu related ---------- */ ++struct ast2700_clk_pll_data { ++ unsigned int parent_id; ++ u32 reg; ++}; + -+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-04-08 18:03:46.629736033 +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. -+ */ ++struct ast2700_clk_fixed_rate_data { ++ unsigned long fixed_rate; ++}; + -+#ifndef VERSION_H -+#define VERSION_H ++struct ast2700_clk_display_fixed_data { ++ u32 reg; ++}; + -+#define TRNG_VERSION "1.00a" ++struct ast2700_clk_info { ++ u32 id; ++ const char *name; ++ u32 reg; ++ u32 type; ++ union { ++ struct ast2700_clk_fixed_factor_data factor; ++ struct ast2700_clk_fixed_rate_data rate; ++ struct ast2700_clk_display_fixed_data display_rate; ++ struct ast2700_clk_gate_data gate; ++ struct ast2700_clk_div_data div; ++ struct ast2700_clk_pll_data pll; ++ struct ast2700_clk_mux_data mux; ++ } data; ++}; + -+#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-04-08 18:03:46.630736014 +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]; ++struct ast2700_clk_data { ++ const struct ast2700_clk_info *clk_info; ++ unsigned int nr_clks; ++ const int scu; +}; + -+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; ++struct ast2700_clk_ctrl { ++ const struct ast2700_clk_data *clk_data; ++ struct device *dev; ++ void __iomem *base; ++ spinlock_t lock; /* clk lock */ ++}; + -+ if (rng == 0) -+ return -1; ++static const struct clk_div_table ast2700_rgmii_div_table[] = { ++ { 0x0, 4 }, ++ { 0x1, 4 }, ++ { 0x2, 6 }, ++ { 0x3, 8 }, ++ { 0x4, 10 }, ++ { 0x5, 12 }, ++ { 0x6, 14 }, ++ { 0x7, 16 }, ++ { 0 } ++}; + -+ pdev = (struct platform_device *)rng->priv; -+ return nisttrng_platform_driver_read(pdev, buf, max, wait); -+} ++static const struct clk_div_table ast2700_rmii_div_table[] = { ++ { 0x0, 8 }, ++ { 0x1, 8 }, ++ { 0x2, 12 }, ++ { 0x3, 16 }, ++ { 0x4, 20 }, ++ { 0x5, 24 }, ++ { 0x6, 28 }, ++ { 0x7, 32 }, ++ { 0 } ++}; + -+static ssize_t ckr_show(struct device *dev, struct device_attribute *devattr, -+ char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++static const struct clk_div_table ast2700_clk_div_table[] = { ++ { 0x0, 2 }, ++ { 0x1, 2 }, ++ { 0x2, 3 }, ++ { 0x3, 4 }, ++ { 0x4, 5 }, ++ { 0x5, 6 }, ++ { 0x6, 7 }, ++ { 0x7, 8 }, ++ { 0 } ++}; + -+ 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 const struct clk_div_table ast2700_clk_div_table2[] = { ++ { 0x0, 2 }, ++ { 0x1, 4 }, ++ { 0x2, 6 }, ++ { 0x3, 8 }, ++ { 0x4, 10 }, ++ { 0x5, 12 }, ++ { 0x6, 14 }, ++ { 0x7, 16 }, ++ { 0 } ++}; + -+static ssize_t features_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++static const struct clk_div_table ast2700_hclk_div_table[] = { ++ { 0x0, 6 }, ++ { 0x1, 5 }, ++ { 0x2, 4 }, ++ { 0x3, 7 }, ++ { 0 } ++}; + -+ 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 const struct clk_div_table ast2700_clk_uart_div_table[] = { ++ { 0x0, 1 }, ++ { 0x1, 13 }, ++ { 0 } ++}; + -+static ssize_t secure_show(struct device *dev, struct device_attribute *devattr, -+ char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++/* soc 0 */ ++static const unsigned int psp_parent_ids[] = { ++ SCU0_CLK_MPLL, ++ SCU0_CLK_HPLL, ++ SCU0_CLK_HPLL, ++ SCU0_CLK_HPLL, ++ SCU0_CLK_MPLL_DIV2, ++ SCU0_CLK_HPLL_DIV2, ++ SCU0_CLK_HPLL, ++ SCU0_CLK_HPLL ++}; + -+ 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 const struct clk_hw *psp_parent_hws[ARRAY_SIZE(psp_parent_ids)]; + -+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; ++static const unsigned int hclk_parent_ids[] = { ++ SCU0_CLK_HPLL, ++ SCU0_CLK_MPLL ++}; + -+ ret = nisttrng_set_secure_mode(&priv->nisttrng, -+ sysfs_streq(buf, "on") ? 1 : 0); -+ if (ret) -+ return -1; ++static const struct clk_hw *hclk_parent_hws[ARRAY_SIZE(hclk_parent_ids)]; + -+ return count; -+} ++static const unsigned int emmc_parent_ids[] = { ++ SCU0_CLK_MPLL_DIV4, ++ SCU0_CLK_HPLL_DIV4 ++}; + -+static ssize_t nonce_show(struct device *dev, struct device_attribute *devattr, -+ char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++static const struct clk_hw *emmc_parent_hws[ARRAY_SIZE(emmc_parent_ids)]; + -+ return sprintf(buf, "%s\n", NIST_TRNG_REG_SMODE_GET_NONCE(pdu_io_read32(priv->nisttrng.base + -+ NIST_TRNG_REG_SMODE)) ? "on" : "off"); -+} ++static const unsigned int mphy_parent_ids[] = { ++ SCU0_CLK_MPLL, ++ SCU0_CLK_HPLL, ++ SCU0_CLK_DPLL, ++ SCU0_CLK_192M ++}; + -+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; ++static const struct clk_hw *mphy_parent_hws[ARRAY_SIZE(mphy_parent_ids)]; + -+ ret = nisttrng_set_nonce_mode(&priv->nisttrng, -+ sysfs_streq(buf, "on") ? 1 : 0); -+ if (ret) -+ return -1; ++static const unsigned int u2phy_parent_ids[] = { ++ SCU0_CLK_MPLL, ++ SCU0_CLK_HPLL ++}; + -+ return count; -+} ++static const struct clk_hw *u2phy_parent_hws[ARRAY_SIZE(u2phy_parent_ids)]; + -+static ssize_t sec_strength_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++static const unsigned int uart_parent_ids[] = { ++ SCU0_CLK_24M, ++ SCU0_CLK_192M ++}; + -+ return sprintf(buf, "%s\n", -+ priv->nisttrng.status.sec_strength ? "256" : "128"); -+} ++static const struct clk_hw *uart_parent_hws[ARRAY_SIZE(uart_parent_ids)]; + -+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; ++/* soc 1 */ ++static const unsigned int uartx_parent_ids[] = { ++ SCU1_CLK_UARTX, ++ SCU1_CLK_HUARTX ++}; + -+ if (count > 8) -+ return -1; ++static const struct clk_hw *uartx_parent_hws[ARRAY_SIZE(uartx_parent_ids)]; + -+ foo[8] = 0; -+ memcpy(foo, buf, 8); -+ ret = kstrtoint(foo, 10, &tmp); -+ if (ret) -+ return ret; ++static const unsigned int uxclk_parent_ids[] = { ++ SCU1_CLK_APLL_DIV4, ++ SCU1_CLK_APLL_DIV2, ++ SCU1_CLK_APLL, ++ SCU1_CLK_HPLL ++}; + -+ ret = nisttrng_set_sec_strength(&priv->nisttrng, tmp); -+ if (ret) -+ return -1; ++static const struct clk_hw *uxclk_parent_hws[ARRAY_SIZE(uxclk_parent_ids)]; + -+ return count; -+} ++static const unsigned int sdclk_parent_ids[] = { ++ SCU1_CLK_HPLL, ++ SCU1_CLK_APLL ++}; + -+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); ++static const struct clk_hw *sdclk_parent_hws[ARRAY_SIZE(sdclk_parent_ids)]; + -+ for (x = 0; x < 4; x++) { -+ sprintf(buf + 8 * x, "%08lx", -+ pdu_io_read32(priv->nisttrng.base + -+ NIST_TRNG_REG_RAND0 + 3 - x)); ++#define FIXED_CLK(_id, _name, _rate) \ ++ { \ ++ .id = _id, \ ++ .type = CLK_FIXED, \ ++ .name = _name, \ ++ .data = { .rate = { .fixed_rate = _rate, } }, \ + } + -+ 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); ++#define FIXED_DISPLAY_CLK(_id, _name, _reg) \ ++ { \ ++ .id = _id, \ ++ .type = CLK_FIXED_DISPLAY, \ ++ .name = _name, \ ++ .data = { .display_rate = { .reg = _reg } }, \ ++ } + -+ for (x = 0; x < 12; x++) { -+ sprintf(buf + 8 * x, "%08lx", -+ pdu_io_read32(priv->nisttrng.base + -+ NIST_TRNG_REG_SEED0 + 11 - x)); ++#define PLL_CLK(_id, _type, _name, _parent_id, _reg) \ ++ { \ ++ .id = _id, \ ++ .type = _type, \ ++ .name = _name, \ ++ .data = { .pll = { \ ++ .parent_id = _parent_id, \ ++ .reg = _reg, \ ++ } }, \ + } -+ 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; ++#define MUX_CLK(_id, _name, _parent_ids, _num_parents, _parent_hws, _reg, _shift, _width) \ ++ { \ ++ .id = _id, \ ++ .type = CLK_MUX, \ ++ .name = _name, \ ++ .data = { \ ++ .mux = { \ ++ .parent_ids = _parent_ids, \ ++ .parent_hws = _parent_hws, \ ++ .num_parents = _num_parents, \ ++ .reg = (_reg), \ ++ .bit_shift = _shift, \ ++ .bit_width = _width, \ ++ }, \ ++ }, \ ++ } + -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_SEED0 + x, -+ tmp); ++#define DIVIDER_CLK(_id, _name, _parent_id, _reg, _shift, _width, _div_table) \ ++ { \ ++ .id = _id, \ ++ .type = CLK_DIVIDER, \ ++ .name = _name, \ ++ .data = { \ ++ .div = { \ ++ .parent_id = _parent_id, \ ++ .reg = _reg, \ ++ .bit_shift = _shift, \ ++ .bit_width = _width, \ ++ .div_table = _div_table, \ ++ }, \ ++ }, \ + } + -+ 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)); ++#define FIXED_FACTOR_CLK(_id, _name, _parent_id, _mult, _div) \ ++ { \ ++ .id = _id, \ ++ .type = CLK_FIXED_FACTOR, \ ++ .name = _name, \ ++ .data = { .factor = { .parent_id = _parent_id, .mult = _mult, .div = _div, } }, \ + } + -+ 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; ++#define GATE_CLK(_id, _type, _name, _parent_id, _reg, _bit, _flags) \ ++ { \ ++ .id = _id, \ ++ .type = _type, \ ++ .name = _name, \ ++ .data = { \ ++ .gate = { \ ++ .parent_id = _parent_id, \ ++ .reg = _reg, \ ++ .bit = _bit, \ ++ .flags = _flags, \ ++ }, \ ++ }, \ ++ } + -+ 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 const struct ast2700_clk_info ast2700_scu0_clk_info[] __initconst = { ++ FIXED_CLK(SCU0_CLKIN, "soc0-clkin", 25 * HZ_PER_MHZ), ++ FIXED_CLK(SCU0_CLK_24M, "soc0-clk24Mhz", 24 * HZ_PER_MHZ), ++ FIXED_CLK(SCU0_CLK_192M, "soc0-clk192Mhz", 192 * HZ_PER_MHZ), ++ FIXED_CLK(SCU0_CLK_U2PHY_CLK12M, "u2phy_clk12m", 12 * HZ_PER_MHZ), ++ FIXED_DISPLAY_CLK(SCU0_CLK_D0, "d0clk", SCU0_D0CLK_PARAM), ++ FIXED_DISPLAY_CLK(SCU0_CLK_D1, "d1clk", SCU0_D1CLK_PARAM), ++ FIXED_DISPLAY_CLK(SCU0_CLK_CRT0, "crt0clk", SCU0_CRT0CLK_PARAM), ++ FIXED_DISPLAY_CLK(SCU0_CLK_CRT1, "crt1clk", SCU0_CRT1CLK_PARAM), ++ PLL_CLK(SCU0_CLK_HPLL, CLK_HPLL, "soc0-hpll", SCU0_CLKIN, SCU0_HPLL_PARAM), ++ PLL_CLK(SCU0_CLK_DPLL, CLK_PLL, "soc0-dpll", SCU0_CLKIN, SCU0_DPLL_PARAM), ++ PLL_CLK(SCU0_CLK_MPLL, CLK_PLL, "soc0-mpll", SCU0_CLKIN, SCU0_MPLL_PARAM), ++ FIXED_FACTOR_CLK(SCU0_CLK_HPLL_DIV2, "soc0-hpll_div2", SCU0_CLK_HPLL, 1, 2), ++ FIXED_FACTOR_CLK(SCU0_CLK_HPLL_DIV4, "soc0-hpll_div4", SCU0_CLK_HPLL, 1, 4), ++ FIXED_FACTOR_CLK(SCU0_CLK_MPLL_DIV2, "soc0-mpll_div2", SCU0_CLK_MPLL, 1, 2), ++ FIXED_FACTOR_CLK(SCU0_CLK_MPLL_DIV4, "soc0-mpll_div4", SCU0_CLK_MPLL, 1, 4), ++ FIXED_FACTOR_CLK(SCU0_CLK_MPLL_DIV8, "soc0-mpll_div8", SCU0_CLK_MPLL, 1, 8), ++ FIXED_FACTOR_CLK(SCU0_CLK_AXI1, "axi1clk", SCU0_CLK_MPLL, 1, 4), ++ MUX_CLK(SCU0_CLK_PSP, "pspclk", psp_parent_ids, ARRAY_SIZE(psp_parent_ids), ++ psp_parent_hws, SCU0_HWSTRAP1, 2, 3), ++ FIXED_FACTOR_CLK(SCU0_CLK_AXI0, "axi0clk", SCU0_CLK_PSP, 1, 2), ++ MUX_CLK(SCU0_CLK_AHBMUX, "soc0-ahbmux", hclk_parent_ids, ARRAY_SIZE(hclk_parent_ids), ++ hclk_parent_hws, SCU0_HWSTRAP1, 7, 1), ++ MUX_CLK(SCU0_CLK_EMMCMUX, "emmcsrc-mux", emmc_parent_ids, ARRAY_SIZE(emmc_parent_ids), ++ emmc_parent_hws, SCU0_CLK_SEL1, 11, 1), ++ MUX_CLK(SCU0_CLK_MPHYSRC, "mphysrc", mphy_parent_ids, ARRAY_SIZE(mphy_parent_ids), ++ mphy_parent_hws, SCU0_CLK_SEL2, 18, 2), ++ MUX_CLK(SCU0_CLK_U2PHY_REFCLKSRC, "u2phy_refclksrc", u2phy_parent_ids, ++ ARRAY_SIZE(u2phy_parent_ids), u2phy_parent_hws, SCU0_CLK_SEL2, 23, 1), ++ MUX_CLK(SCU0_CLK_UART, "soc0-uartclk", uart_parent_ids, ARRAY_SIZE(uart_parent_ids), ++ uart_parent_hws, SCU0_CLK_SEL2, 14, 1), ++ PLL_CLK(SCU0_CLK_MPHY, CLK_MISC, "mphyclk", SCU0_CLK_MPHYSRC, SCU0_MPHYCLK_PARAM), ++ PLL_CLK(SCU0_CLK_U2PHY_REFCLK, CLK_MISC, "u2phy_refclk", SCU0_CLK_U2PHY_REFCLKSRC, ++ SCU0_CLK_SEL2), ++ DIVIDER_CLK(SCU0_CLK_AHB, "soc0-ahb", SCU0_CLK_AHBMUX, ++ SCU0_HWSTRAP1, 5, 2, ast2700_hclk_div_table), ++ DIVIDER_CLK(SCU0_CLK_EMMC, "emmcclk", SCU0_CLK_EMMCMUX, ++ SCU0_CLK_SEL1, 12, 3, ast2700_clk_div_table2), ++ DIVIDER_CLK(SCU0_CLK_APB, "soc0-apb", SCU0_CLK_AXI0, ++ SCU0_CLK_SEL1, 23, 3, ast2700_clk_div_table2), ++ DIVIDER_CLK(SCU0_CLK_HPLL_DIV_AHB, "soc0-hpll-ahb", SCU0_CLK_HPLL, ++ SCU0_HWSTRAP1, 5, 2, ast2700_hclk_div_table), ++ DIVIDER_CLK(SCU0_CLK_MPLL_DIV_AHB, "soc0-mpll-ahb", SCU0_CLK_MPLL, ++ SCU0_HWSTRAP1, 5, 2, ast2700_hclk_div_table), ++ DIVIDER_CLK(SCU0_CLK_UART4, "uart4clk", SCU0_CLK_UART, ++ SCU0_CLK_SEL2, 30, 1, ast2700_clk_uart_div_table), ++ GATE_CLK(SCU0_CLK_GATE_MCLK, CLK_GATE_ASPEED, "mclk-gate", SCU0_CLK_MPLL, ++ SCU0_CLK_STOP, 0, CLK_IS_CRITICAL), ++ GATE_CLK(SCU0_CLK_GATE_ECLK, CLK_GATE_ASPEED, "eclk-gate", -1, SCU0_CLK_STOP, 1, 0), ++ GATE_CLK(SCU0_CLK_GATE_2DCLK, CLK_GATE_ASPEED, "gclk-gate", -1, SCU0_CLK_STOP, 2, 0), ++ GATE_CLK(SCU0_CLK_GATE_VCLK, CLK_GATE_ASPEED, "vclk-gate", -1, SCU0_CLK_STOP, 3, 0), ++ GATE_CLK(SCU0_CLK_GATE_BCLK, CLK_GATE_ASPEED, "bclk-gate", -1, ++ SCU0_CLK_STOP, 4, CLK_IS_CRITICAL), ++ GATE_CLK(SCU0_CLK_GATE_VGA0CLK, CLK_GATE_ASPEED, "vga0clk-gate", -1, ++ SCU0_CLK_STOP, 5, CLK_IS_CRITICAL), ++ GATE_CLK(SCU0_CLK_GATE_REFCLK, CLK_GATE_ASPEED, "soc0-refclk-gate", SCU0_CLKIN, ++ SCU0_CLK_STOP, 6, CLK_IS_CRITICAL), ++ GATE_CLK(SCU0_CLK_GATE_PORTBUSB2CLK, CLK_GATE_ASPEED, "portb-usb2clk-gate", -1, ++ SCU0_CLK_STOP, 7, 0), ++ GATE_CLK(SCU0_CLK_GATE_UHCICLK, CLK_GATE_ASPEED, "uhciclk-gate", -1, SCU0_CLK_STOP, 9, 0), ++ GATE_CLK(SCU0_CLK_GATE_VGA1CLK, CLK_GATE_ASPEED, "vga1clk-gate", -1, ++ SCU0_CLK_STOP, 10, CLK_IS_CRITICAL), ++ GATE_CLK(SCU0_CLK_GATE_DDRPHYCLK, CLK_GATE_ASPEED, "ddrphy-gate", -1, ++ SCU0_CLK_STOP, 11, CLK_IS_CRITICAL), ++ GATE_CLK(SCU0_CLK_GATE_E2M0CLK, CLK_GATE_ASPEED, "e2m0clk-gate", -1, ++ SCU0_CLK_STOP, 12, CLK_IS_CRITICAL), ++ GATE_CLK(SCU0_CLK_GATE_HACCLK, CLK_GATE_ASPEED, "hacclk-gate", -1, SCU0_CLK_STOP, 13, 0), ++ GATE_CLK(SCU0_CLK_GATE_PORTAUSB2CLK, CLK_GATE_ASPEED, "porta-usb2clk-gate", -1, ++ SCU0_CLK_STOP, 14, 0), ++ GATE_CLK(SCU0_CLK_GATE_UART4CLK, CLK_GATE_ASPEED, "uart4clk-gate", SCU0_CLK_UART4, ++ SCU0_CLK_STOP, 15, CLK_IS_CRITICAL), ++ GATE_CLK(SCU0_CLK_GATE_SLICLK, CLK_GATE_ASPEED, "soc0-sliclk-gate", -1, ++ SCU0_CLK_STOP, 16, CLK_IS_CRITICAL), ++ GATE_CLK(SCU0_CLK_GATE_DACCLK, CLK_GATE_ASPEED, "dacclk-gate", -1, ++ SCU0_CLK_STOP, 17, CLK_IS_CRITICAL), ++ GATE_CLK(SCU0_CLK_GATE_DP, CLK_GATE_ASPEED, "dpclk-gate", -1, ++ SCU0_CLK_STOP, 18, CLK_IS_CRITICAL), ++ GATE_CLK(SCU0_CLK_GATE_E2M1CLK, CLK_GATE_ASPEED, "e2m1clk-gate", -1, ++ SCU0_CLK_STOP, 19, CLK_IS_CRITICAL), ++ GATE_CLK(SCU0_CLK_GATE_CRT0CLK, CLK_GATE_ASPEED, "crt0clk-gate", -1, ++ SCU0_CLK_STOP, 20, 0), ++ GATE_CLK(SCU0_CLK_GATE_CRT1CLK, CLK_GATE_ASPEED, "crt1clk-gate", -1, ++ SCU0_CLK_STOP, 21, 0), ++ GATE_CLK(SCU0_CLK_GATE_ECDSACLK, CLK_GATE_ASPEED, "eccclk-gate", -1, ++ SCU0_CLK_STOP, 23, 0), ++ GATE_CLK(SCU0_CLK_GATE_RSACLK, CLK_GATE_ASPEED, "rsaclk-gate", -1, ++ SCU0_CLK_STOP, 24, 0), ++ GATE_CLK(SCU0_CLK_GATE_RVAS0CLK, CLK_GATE_ASPEED, "rvas0clk-gate", -1, ++ SCU0_CLK_STOP, 25, 0), ++ GATE_CLK(SCU0_CLK_GATE_UFSCLK, CLK_GATE_ASPEED, "ufsclk-gate", -1, ++ SCU0_CLK_STOP, 26, 0), ++ GATE_CLK(SCU0_CLK_GATE_EMMCCLK, CLK_GATE_ASPEED, "emmcclk-gate", SCU0_CLK_EMMC, ++ SCU0_CLK_STOP, 27, 0), ++ GATE_CLK(SCU0_CLK_GATE_RVAS1CLK, CLK_GATE_ASPEED, "rvas1clk-gate", -1, ++ SCU0_CLK_STOP, 28, 0), ++}; + -+static ssize_t ctrl_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++static const struct ast2700_clk_info ast2700_scu1_clk_info[] __initconst = { ++ FIXED_CLK(SCU1_CLKIN, "soc1-clkin", 25 * HZ_PER_MHZ), ++ 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_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), ++ DIVIDER_CLK(SCU1_CLK_APB, "soc1-apb", SCU1_CLK_HPLL, ++ SCU1_CLK_SEL1, 18, 3, ast2700_clk_div_table2), ++ DIVIDER_CLK(SCU1_CLK_RMII, "rmii", SCU1_CLK_HPLL, ++ SCU1_CLK_SEL1, 21, 3, ast2700_rmii_div_table), ++ DIVIDER_CLK(SCU1_CLK_RGMII, "rgmii", SCU1_CLK_HPLL, ++ SCU1_CLK_SEL1, 25, 3, ast2700_rgmii_div_table), ++ DIVIDER_CLK(SCU1_CLK_MACHCLK, "machclk", SCU1_CLK_HPLL, ++ SCU1_CLK_SEL1, 29, 3, ast2700_clk_div_table), ++ DIVIDER_CLK(SCU1_CLK_APLL_DIVN, "soc1-apll_divn", ++ SCU1_CLK_APLL, SCU1_CLK_SEL2, 8, 3, ast2700_clk_div_table), ++ DIVIDER_CLK(SCU1_CLK_AHB, "soc1-ahb", SCU1_CLK_HPLL, ++ SCU1_CLK_SEL2, 20, 3, ast2700_clk_div_table), ++ DIVIDER_CLK(SCU1_CLK_I3C, "soc1-i3c", SCU1_CLK_HPLL, ++ SCU1_CLK_SEL2, 23, 3, ast2700_clk_div_table), ++ MUX_CLK(SCU1_CLK_SDMUX, "sdclk-mux", sdclk_parent_ids, ARRAY_SIZE(sdclk_parent_ids), ++ sdclk_parent_hws, SCU1_CLK_SEL1, 13, 1), ++ MUX_CLK(SCU1_CLK_UXCLK, "uxclk", uxclk_parent_ids, ARRAY_SIZE(uxclk_parent_ids), ++ 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), ++ 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), ++ PLL_CLK(SCU1_CLK_HUARTX, CLK_UART_PLL, "huartxclk", SCU1_CLK_HUXCLK, SCU1_HUXCLK_CTRL), ++ MUX_CLK(SCU1_CLK_UART0, "uart0clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 0, 1), ++ MUX_CLK(SCU1_CLK_UART1, "uart1clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 1, 1), ++ MUX_CLK(SCU1_CLK_UART2, "uart2clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 2, 1), ++ MUX_CLK(SCU1_CLK_UART3, "uart3clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 3, 1), ++ MUX_CLK(SCU1_CLK_UART5, "uart5clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 5, 1), ++ MUX_CLK(SCU1_CLK_UART6, "uart6clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 6, 1), ++ MUX_CLK(SCU1_CLK_UART7, "uart7clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 7, 1), ++ MUX_CLK(SCU1_CLK_UART8, "uart8clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 8, 1), ++ MUX_CLK(SCU1_CLK_UART9, "uart9clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 9, 1), ++ MUX_CLK(SCU1_CLK_UART10, "uart10clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 10, 1), ++ MUX_CLK(SCU1_CLK_UART11, "uart11clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 11, 1), ++ MUX_CLK(SCU1_CLK_UART12, "uart12clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 12, 1), ++ FIXED_FACTOR_CLK(SCU1_CLK_UART13, "uart13clk", SCU1_CLK_HUARTX, 1, 1), ++ FIXED_FACTOR_CLK(SCU1_CLK_UART14, "uart14clk", SCU1_CLK_HUARTX, 1, 1), ++ GATE_CLK(SCU1_CLK_MAC0RCLK, CLK_GATE, "mac0rclk-gate", SCU1_CLK_RMII, ++ SCU1_MAC12_CLK_DLY, 29, 0), ++ GATE_CLK(SCU1_CLK_MAC1RCLK, CLK_GATE, "mac1rclk-gate", SCU1_CLK_RMII, ++ SCU1_MAC12_CLK_DLY, 30, 0), ++ GATE_CLK(SCU1_CLK_GATE_LCLK0, CLK_GATE_ASPEED, "lclk0-gate", -1, ++ SCU1_CLK_STOP, 0, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_LCLK1, CLK_GATE_ASPEED, "lclk1-gate", -1, ++ SCU1_CLK_STOP, 1, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_ESPI0CLK, CLK_GATE_ASPEED, "espi0clk-gate", -1, ++ SCU1_CLK_STOP, 2, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_ESPI1CLK, CLK_GATE_ASPEED, "espi1clk-gate", -1, ++ SCU1_CLK_STOP, 3, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_SDCLK, CLK_GATE_ASPEED, "sdclk-gate", SCU1_CLK_SDCLK, ++ SCU1_CLK_STOP, 4, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_IPEREFCLK, CLK_GATE_ASPEED, "soc1-iperefclk-gate", -1, ++ SCU1_CLK_STOP, 5, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_REFCLK, CLK_GATE_ASPEED, "soc1-refclk-gate", -1, ++ SCU1_CLK_STOP, 6, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_LPCHCLK, CLK_GATE_ASPEED, "lpchclk-gate", -1, ++ SCU1_CLK_STOP, 7, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_MAC0CLK, CLK_GATE_ASPEED, "mac0clk-gate", -1, ++ SCU1_CLK_STOP, 8, 0), ++ GATE_CLK(SCU1_CLK_GATE_MAC1CLK, CLK_GATE_ASPEED, "mac1clk-gate", -1, ++ SCU1_CLK_STOP, 9, 0), ++ GATE_CLK(SCU1_CLK_GATE_MAC2CLK, CLK_GATE_ASPEED, "mac2clk-gate", -1, ++ SCU1_CLK_STOP, 10, 0), ++ GATE_CLK(SCU1_CLK_GATE_UART0CLK, CLK_GATE_ASPEED, "uart0clk-gate", SCU1_CLK_UART0, ++ SCU1_CLK_STOP, 11, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_UART1CLK, CLK_GATE_ASPEED, "uart1clk-gate", SCU1_CLK_UART1, ++ SCU1_CLK_STOP, 12, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_UART2CLK, CLK_GATE_ASPEED, "uart2clk-gate", SCU1_CLK_UART2, ++ SCU1_CLK_STOP, 13, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_UART3CLK, CLK_GATE_ASPEED, "uart3clk-gate", SCU1_CLK_UART3, ++ SCU1_CLK_STOP, 14, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_I2CCLK, CLK_GATE_ASPEED, "i2cclk-gate", -1, SCU1_CLK_STOP, 15, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C0CLK, CLK_GATE_ASPEED, "i3c0clk-gate", SCU1_CLK_I3C, ++ SCU1_CLK_STOP, 16, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C1CLK, CLK_GATE_ASPEED, "i3c1clk-gate", SCU1_CLK_I3C, ++ SCU1_CLK_STOP, 17, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C2CLK, CLK_GATE_ASPEED, "i3c2clk-gate", SCU1_CLK_I3C, ++ SCU1_CLK_STOP, 18, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C3CLK, CLK_GATE_ASPEED, "i3c3clk-gate", SCU1_CLK_I3C, ++ SCU1_CLK_STOP, 19, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C4CLK, CLK_GATE_ASPEED, "i3c4clk-gate", SCU1_CLK_I3C, ++ SCU1_CLK_STOP, 20, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C5CLK, CLK_GATE_ASPEED, "i3c5clk-gate", SCU1_CLK_I3C, ++ SCU1_CLK_STOP, 21, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C6CLK, CLK_GATE_ASPEED, "i3c6clk-gate", SCU1_CLK_I3C, ++ SCU1_CLK_STOP, 22, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C7CLK, CLK_GATE_ASPEED, "i3c7clk-gate", SCU1_CLK_I3C, ++ SCU1_CLK_STOP, 23, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C8CLK, CLK_GATE_ASPEED, "i3c8clk-gate", SCU1_CLK_I3C, ++ SCU1_CLK_STOP, 24, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C9CLK, CLK_GATE_ASPEED, "i3c9clk-gate", SCU1_CLK_I3C, ++ SCU1_CLK_STOP, 25, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C10CLK, CLK_GATE_ASPEED, "i3c10clk-gate", SCU1_CLK_I3C, ++ SCU1_CLK_STOP, 26, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C11CLK, CLK_GATE_ASPEED, "i3c11clk-gate", SCU1_CLK_I3C, ++ SCU1_CLK_STOP, 27, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C12CLK, CLK_GATE_ASPEED, "i3c12clk-gate", SCU1_CLK_I3C, ++ SCU1_CLK_STOP, 28, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C13CLK, CLK_GATE_ASPEED, "i3c13clk-gate", SCU1_CLK_I3C, ++ SCU1_CLK_STOP, 29, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C14CLK, CLK_GATE_ASPEED, "i3c14clk-gate", SCU1_CLK_I3C, ++ SCU1_CLK_STOP, 30, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C15CLK, CLK_GATE_ASPEED, "i3c15clk-gate", SCU1_CLK_I3C, ++ SCU1_CLK_STOP, 31, 0), ++ GATE_CLK(SCU1_CLK_GATE_UART5CLK, CLK_GATE_ASPEED, "uart5clk-gate", SCU1_CLK_UART5, ++ SCU1_CLK_STOP2, 0, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_UART6CLK, CLK_GATE_ASPEED, "uart6clk-gate", SCU1_CLK_UART6, ++ SCU1_CLK_STOP2, 1, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_UART7CLK, CLK_GATE_ASPEED, "uart7clk-gate", SCU1_CLK_UART7, ++ SCU1_CLK_STOP2, 2, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_UART8CLK, CLK_GATE_ASPEED, "uart8clk-gate", SCU1_CLK_UART8, ++ SCU1_CLK_STOP2, 3, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_UART9CLK, CLK_GATE_ASPEED, "uart9clk-gate", SCU1_CLK_UART9, ++ SCU1_CLK_STOP2, 4, 0), ++ GATE_CLK(SCU1_CLK_GATE_UART10CLK, CLK_GATE_ASPEED, "uart10clk-gate", SCU1_CLK_UART10, ++ SCU1_CLK_STOP2, 5, 0), ++ GATE_CLK(SCU1_CLK_GATE_UART11CLK, CLK_GATE_ASPEED, "uart11clk-gate", SCU1_CLK_UART11, ++ SCU1_CLK_STOP2, 6, 0), ++ GATE_CLK(SCU1_CLK_GATE_UART12CLK, CLK_GATE_ASPEED, "uart12clk-gate", SCU1_CLK_UART12, ++ SCU1_CLK_STOP2, 7, 0), ++ GATE_CLK(SCU1_CLK_GATE_FSICLK, CLK_GATE_ASPEED, "fsiclk-gate", -1, SCU1_CLK_STOP2, 8, 0), ++ GATE_CLK(SCU1_CLK_GATE_LTPIPHYCLK, CLK_GATE_ASPEED, "ltpiphyclk-gate", -1, ++ SCU1_CLK_STOP2, 9, 0), ++ GATE_CLK(SCU1_CLK_GATE_LTPICLK, CLK_GATE_ASPEED, "ltpiclk-gate", -1, ++ SCU1_CLK_STOP2, 10, 0), ++ GATE_CLK(SCU1_CLK_GATE_VGALCLK, CLK_GATE_ASPEED, "vgalclk-gate", -1, ++ SCU1_CLK_STOP2, 11, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_UHCICLK, CLK_GATE_ASPEED, "usbuartclk-gate", -1, ++ SCU1_CLK_STOP2, 12, 0), ++ GATE_CLK(SCU1_CLK_GATE_CANCLK, CLK_GATE_ASPEED, "canclk-gate", SCU1_CLK_CAN, ++ SCU1_CLK_STOP2, 13, 0), ++ GATE_CLK(SCU1_CLK_GATE_PCICLK, CLK_GATE_ASPEED, "pciclk-gate", -1, ++ SCU1_CLK_STOP2, 14, 0), ++ GATE_CLK(SCU1_CLK_GATE_SLICLK, CLK_GATE_ASPEED, "soc1-sliclk-gate", -1, ++ SCU1_CLK_STOP2, 15, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_E2MCLK, CLK_GATE_ASPEED, "soc1-e2m-gate", -1, ++ SCU1_CLK_STOP2, 16, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_PORTCUSB2CLK, CLK_GATE_ASPEED, "portcusb2-gate", -1, ++ SCU1_CLK_STOP2, 17, 0), ++ GATE_CLK(SCU1_CLK_GATE_PORTDUSB2CLK, CLK_GATE_ASPEED, "portdusb2-gate", -1, ++ SCU1_CLK_STOP2, 18, 0), ++ GATE_CLK(SCU1_CLK_GATE_LTPI1TXCLK, CLK_GATE_ASPEED, "ltp1tx-gate", -1, ++ SCU1_CLK_STOP2, 19, 0), ++}; + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_CTRL)); -+} ++static const struct ast2700_clk_info ast2755_scu1_clk_info[] __initconst = { ++ FIXED_CLK(SCU1_CLKIN, "soc1-clkin", 25 * HZ_PER_MHZ), ++ 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_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), ++ DIVIDER_CLK(SCU1_CLK_APB, "soc1-apb", SCU1_CLK_HPLL, ++ SCU1_CLK_SEL1, 18, 3, ast2700_clk_div_table2), ++ DIVIDER_CLK(SCU1_CLK_RMII, "rmii", SCU1_CLK_HPLL, ++ SCU1_CLK_SEL1, 21, 3, ast2700_rmii_div_table), ++ DIVIDER_CLK(SCU1_CLK_RGMII, "rgmii", SCU1_CLK_HPLL, ++ SCU1_CLK_SEL1, 25, 3, ast2700_rgmii_div_table), ++ DIVIDER_CLK(SCU1_CLK_MACHCLK, "machclk", SCU1_CLK_HPLL, ++ SCU1_CLK_SEL1, 29, 3, ast2700_clk_div_table), ++ DIVIDER_CLK(SCU1_CLK_APLL_DIVN, "soc1-apll_divn", ++ SCU1_CLK_APLL, SCU1_CLK_SEL2, 8, 3, ast2700_clk_div_table), ++ DIVIDER_CLK(SCU1_CLK_AHB, "soc1-ahb", SCU1_CLK_HPLL, ++ SCU1_CLK_SEL2, 20, 3, ast2700_clk_div_table), ++ DIVIDER_CLK(SCU1_CLK_I3C, "soc1-i3c", SCU1_CLK_HPLL, ++ SCU1_CLK_SEL2, 23, 3, ast2700_clk_div_table), ++ MUX_CLK(SCU1_CLK_SDMUX, "sdclk-mux", sdclk_parent_ids, ARRAY_SIZE(sdclk_parent_ids), ++ sdclk_parent_hws, SCU1_CLK_SEL1, 13, 1), ++ MUX_CLK(SCU1_CLK_UXCLK, "uxclk", uxclk_parent_ids, ARRAY_SIZE(uxclk_parent_ids), ++ 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), ++ 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), ++ PLL_CLK(SCU1_CLK_HUARTX, CLK_UART_PLL, "huartxclk", SCU1_CLK_HUXCLK, SCU1_HUXCLK_CTRL), ++ MUX_CLK(SCU1_CLK_UART0, "uart0clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 0, 1), ++ MUX_CLK(SCU1_CLK_UART1, "uart1clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 1, 1), ++ MUX_CLK(SCU1_CLK_UART2, "uart2clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 2, 1), ++ MUX_CLK(SCU1_CLK_UART3, "uart3clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 3, 1), ++ MUX_CLK(SCU1_CLK_UART5, "uart5clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 5, 1), ++ MUX_CLK(SCU1_CLK_UART6, "uart6clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 6, 1), ++ MUX_CLK(SCU1_CLK_UART7, "uart7clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 7, 1), ++ MUX_CLK(SCU1_CLK_UART8, "uart8clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 8, 1), ++ MUX_CLK(SCU1_CLK_UART9, "uart9clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 9, 1), ++ MUX_CLK(SCU1_CLK_UART10, "uart10clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 10, 1), ++ MUX_CLK(SCU1_CLK_UART11, "uart11clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 11, 1), ++ MUX_CLK(SCU1_CLK_UART12, "uart12clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), ++ uartx_parent_hws, SCU1_CLK_SEL1, 12, 1), ++ FIXED_FACTOR_CLK(SCU1_CLK_UART13, "uart13clk", SCU1_CLK_HUARTX, 1, 1), ++ FIXED_FACTOR_CLK(SCU1_CLK_UART14, "uart14clk", SCU1_CLK_HUARTX, 1, 1), ++ GATE_CLK(SCU1_CLK_MAC0RCLK, CLK_GATE, "mac0rclk-gate", SCU1_CLK_RMII, ++ SCU1_MAC12_CLK_DLY, 29, 0), ++ GATE_CLK(SCU1_CLK_MAC1RCLK, CLK_GATE, "mac1rclk-gate", SCU1_CLK_RMII, ++ SCU1_MAC12_CLK_DLY, 30, 0), ++ GATE_CLK(SCU1_CLK_GATE_LCLK0, CLK_GATE_ASPEED, "lclk0-gate", -1, ++ SCU1_CLK_STOP, 0, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_LCLK1, CLK_GATE_ASPEED, "lclk1-gate", -1, ++ AST2755_SCU1_CLK_STOP, 1, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_ESPI0CLK, CLK_GATE_ASPEED, "espi0clk-gate", -1, ++ AST2755_SCU1_CLK_STOP, 2, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_ESPI1CLK, CLK_GATE_ASPEED, "espi1clk-gate", -1, ++ AST2755_SCU1_CLK_STOP, 3, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_SDCLK, CLK_GATE_ASPEED, "sdclk-gate", SCU1_CLK_SDCLK, ++ AST2755_SCU1_CLK_STOP, 4, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_IPEREFCLK, CLK_GATE_ASPEED, "soc1-iperefclk-gate", -1, ++ AST2755_SCU1_CLK_STOP, 5, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_REFCLK, CLK_GATE_ASPEED, "soc1-refclk-gate", -1, ++ AST2755_SCU1_CLK_STOP, 6, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_LPCHCLK, CLK_GATE_ASPEED, "lpchclk-gate", -1, ++ AST2755_SCU1_CLK_STOP, 7, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_MAC0CLK, CLK_GATE_ASPEED, "mac0clk-gate", -1, ++ AST2755_SCU1_CLK_STOP, 8, 0), ++ GATE_CLK(SCU1_CLK_GATE_MAC1CLK, CLK_GATE_ASPEED, "mac1clk-gate", -1, ++ AST2755_SCU1_CLK_STOP, 9, 0), ++ GATE_CLK(SCU1_CLK_GATE_MAC2CLK, CLK_GATE_ASPEED, "mac2clk-gate", -1, ++ AST2755_SCU1_CLK_STOP, 10, 0), ++ GATE_CLK(SCU1_CLK_GATE_UART0CLK, CLK_GATE_ASPEED, "uart0clk-gate", SCU1_CLK_UART0, ++ AST2755_SCU1_CLK_STOP, 11, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_UART1CLK, CLK_GATE_ASPEED, "uart1clk-gate", SCU1_CLK_UART1, ++ AST2755_SCU1_CLK_STOP, 12, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_UART2CLK, CLK_GATE_ASPEED, "uart2clk-gate", SCU1_CLK_UART2, ++ AST2755_SCU1_CLK_STOP, 13, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_UART3CLK, CLK_GATE_ASPEED, "uart3clk-gate", SCU1_CLK_UART3, ++ AST2755_SCU1_CLK_STOP, 14, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_I2CCLK, CLK_GATE_ASPEED, "i2cclk-gate", -1, SCU1_CLK_STOP, 15, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C0CLK, CLK_GATE_ASPEED, "i3c0clk-gate", SCU1_CLK_I3C, ++ AST2755_SCU1_CLK_STOP, 16, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C1CLK, CLK_GATE_ASPEED, "i3c1clk-gate", SCU1_CLK_I3C, ++ AST2755_SCU1_CLK_STOP, 17, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C2CLK, CLK_GATE_ASPEED, "i3c2clk-gate", SCU1_CLK_I3C, ++ AST2755_SCU1_CLK_STOP, 18, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C3CLK, CLK_GATE_ASPEED, "i3c3clk-gate", SCU1_CLK_I3C, ++ AST2755_SCU1_CLK_STOP, 19, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C4CLK, CLK_GATE_ASPEED, "i3c4clk-gate", SCU1_CLK_I3C, ++ AST2755_SCU1_CLK_STOP, 20, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C5CLK, CLK_GATE_ASPEED, "i3c5clk-gate", SCU1_CLK_I3C, ++ AST2755_SCU1_CLK_STOP, 21, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C6CLK, CLK_GATE_ASPEED, "i3c6clk-gate", SCU1_CLK_I3C, ++ AST2755_SCU1_CLK_STOP, 22, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C7CLK, CLK_GATE_ASPEED, "i3c7clk-gate", SCU1_CLK_I3C, ++ AST2755_SCU1_CLK_STOP, 23, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C8CLK, CLK_GATE_ASPEED, "i3c8clk-gate", SCU1_CLK_I3C, ++ AST2755_SCU1_CLK_STOP, 24, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C9CLK, CLK_GATE_ASPEED, "i3c9clk-gate", SCU1_CLK_I3C, ++ AST2755_SCU1_CLK_STOP, 25, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C10CLK, CLK_GATE_ASPEED, "i3c10clk-gate", SCU1_CLK_I3C, ++ AST2755_SCU1_CLK_STOP, 26, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C11CLK, CLK_GATE_ASPEED, "i3c11clk-gate", SCU1_CLK_I3C, ++ AST2755_SCU1_CLK_STOP, 27, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C12CLK, CLK_GATE_ASPEED, "i3c12clk-gate", SCU1_CLK_I3C, ++ AST2755_SCU1_CLK_STOP, 28, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C13CLK, CLK_GATE_ASPEED, "i3c13clk-gate", SCU1_CLK_I3C, ++ AST2755_SCU1_CLK_STOP, 29, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C14CLK, CLK_GATE_ASPEED, "i3c14clk-gate", SCU1_CLK_I3C, ++ AST2755_SCU1_CLK_STOP, 30, 0), ++ GATE_CLK(SCU1_CLK_GATE_I3C15CLK, CLK_GATE_ASPEED, "i3c15clk-gate", SCU1_CLK_I3C, ++ AST2755_SCU1_CLK_STOP, 31, 0), ++ GATE_CLK(SCU1_CLK_GATE_UART5CLK, CLK_GATE_ASPEED, "uart5clk-gate", SCU1_CLK_UART5, ++ AST2755_SCU1_CLK_STOP, 0, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_UART6CLK, CLK_GATE_ASPEED, "uart6clk-gate", SCU1_CLK_UART6, ++ AST2755_SCU1_CLK_STOP, 1, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_UART7CLK, CLK_GATE_ASPEED, "uart7clk-gate", SCU1_CLK_UART7, ++ AST2755_SCU1_CLK_STOP, 2, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_UART8CLK, CLK_GATE_ASPEED, "uart8clk-gate", SCU1_CLK_UART8, ++ AST2755_SCU1_CLK_STOP, 3, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_UART9CLK, CLK_GATE_ASPEED, "uart9clk-gate", SCU1_CLK_UART9, ++ AST2755_SCU1_CLK_STOP, 4, 0), ++ GATE_CLK(SCU1_CLK_GATE_UART10CLK, CLK_GATE_ASPEED, "uart10clk-gate", SCU1_CLK_UART10, ++ AST2755_SCU1_CLK_STOP, 5, 0), ++ GATE_CLK(SCU1_CLK_GATE_UART11CLK, CLK_GATE_ASPEED, "uart11clk-gate", SCU1_CLK_UART11, ++ AST2755_SCU1_CLK_STOP, 6, 0), ++ GATE_CLK(SCU1_CLK_GATE_UART12CLK, CLK_GATE_ASPEED, "uart12clk-gate", SCU1_CLK_UART12, ++ AST2755_SCU1_CLK_STOP, 7, 0), ++ GATE_CLK(SCU1_CLK_GATE_FSICLK, CLK_GATE_ASPEED, "fsiclk-gate", -1, SCU1_CLK_STOP2, 8, 0), ++ GATE_CLK(SCU1_CLK_GATE_LTPIPHYCLK, CLK_GATE_ASPEED, "ltpiphyclk-gate", -1, ++ AST2755_SCU1_CLK_STOP, 9, 0), ++ GATE_CLK(SCU1_CLK_GATE_LTPICLK, CLK_GATE_ASPEED, "ltpiclk-gate", -1, ++ AST2755_SCU1_CLK_STOP, 10, 0), ++ GATE_CLK(SCU1_CLK_GATE_VGALCLK, CLK_GATE_ASPEED, "vgalclk-gate", -1, ++ AST2755_SCU1_CLK_STOP, 11, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_UHCICLK, CLK_GATE_ASPEED, "usbuartclk-gate", -1, ++ AST2755_SCU1_CLK_STOP, 12, 0), ++ GATE_CLK(SCU1_CLK_GATE_CANCLK, CLK_GATE_ASPEED, "canclk-gate", SCU1_CLK_CAN, ++ AST2755_SCU1_CLK_STOP, 13, 0), ++ GATE_CLK(SCU1_CLK_GATE_PCICLK, CLK_GATE_ASPEED, "pciclk-gate", -1, ++ AST2755_SCU1_CLK_STOP, 14, 0), ++ GATE_CLK(SCU1_CLK_GATE_SLICLK, CLK_GATE_ASPEED, "soc1-sliclk-gate", -1, ++ AST2755_SCU1_CLK_STOP, 15, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_E2MCLK, CLK_GATE_ASPEED, "soc1-e2m-gate", -1, ++ AST2755_SCU1_CLK_STOP, 16, CLK_IS_CRITICAL), ++ GATE_CLK(SCU1_CLK_GATE_PORTCUSB2CLK, CLK_GATE_ASPEED, "portcusb2-gate", -1, ++ AST2755_SCU1_CLK_STOP, 17, 0), ++ GATE_CLK(SCU1_CLK_GATE_PORTDUSB2CLK, CLK_GATE_ASPEED, "portdusb2-gate", -1, ++ AST2755_SCU1_CLK_STOP, 18, 0), ++ GATE_CLK(SCU1_CLK_GATE_LTPI1TXCLK, CLK_GATE_ASPEED, "ltp1tx-gate", -1, ++ AST2755_SCU1_CLK_STOP, 19, 0), ++}; + -+static ssize_t ctrl_reg_store(struct device *dev, -+ struct device_attribute *devattr, const char *buf, -+ size_t count) ++static struct clk_hw *ast2700_clk_hw_register_fixed_display(void __iomem *reg, const char *name, ++ struct ast2700_clk_ctrl *clk_ctrl) +{ -+ 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; ++ unsigned int mult, div, r, n; ++ u32 xdclk; ++ u32 val; + -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_CTRL, tmp); -+ return count; -+} ++ val = readl(clk_ctrl->base + SCU0_CLK_SEL2); ++ if (val & BIT(29)) ++ xdclk = 800 * HZ_PER_MHZ; ++ else ++ xdclk = 1000 * HZ_PER_MHZ; + -+static ssize_t istat_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ val = readl(reg); ++ r = val & GENMASK(15, 0); ++ n = (val >> 16) & GENMASK(15, 0); ++ mult = r; ++ div = 2 * n; + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_ISTAT)); ++ return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL, 0, (xdclk * mult) / div); +} + -+static ssize_t istat_reg_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) ++static struct clk_hw *ast2700_clk_hw_register_hpll(void __iomem *reg, ++ const char *name, const struct clk_hw *parent_hw, ++ struct ast2700_clk_ctrl *clk_ctrl) +{ -+ 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; ++ unsigned int mult, div; ++ u32 val; + -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_ISTAT, tmp); -+ return count; -+} ++ val = readl(clk_ctrl->base + SCU0_HWSTRAP1); ++ if ((readl(clk_ctrl->base) & REVISION_ID) && (val & BIT(3))) { ++ switch ((val & GENMASK(4, 2)) >> 2) { ++ case 2: ++ return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL, ++ 0, 1800 * HZ_PER_MHZ); ++ case 3: ++ return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL, ++ 0, 1700 * HZ_PER_MHZ); ++ case 6: ++ return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL, ++ 0, 1200 * HZ_PER_MHZ); ++ case 7: ++ return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL, ++ 0, 800 * HZ_PER_MHZ); ++ default: ++ return ERR_PTR(-EINVAL); ++ } ++ } else if ((val & GENMASK(3, 2)) != 0) { ++ switch ((val & GENMASK(3, 2)) >> 2) { ++ case 1: ++ return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL, ++ 0, 1900 * HZ_PER_MHZ); ++ case 2: ++ return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL, ++ 0, 1800 * HZ_PER_MHZ); ++ case 3: ++ return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL, ++ 0, 1700 * HZ_PER_MHZ); ++ default: ++ return ERR_PTR(-EINVAL); ++ } ++ } else { ++ val = readl(reg); + -+static ssize_t mode_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ if (val & BIT(24)) { ++ /* Pass through mode */ ++ mult = 1; ++ div = 1; ++ } else { ++ u32 m = val & 0x1fff; ++ u32 n = (val >> 13) & 0x3f; ++ u32 p = (val >> 19) & 0xf; + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_MODE)); ++ mult = (m + 1) / (2 * (n + 1)); ++ div = p + 1; ++ } ++ } ++ ++ return devm_clk_hw_register_fixed_factor_parent_hw(clk_ctrl->dev, name, ++ parent_hw, 0, mult, div); +} + -+static ssize_t mode_reg_store(struct device *dev, -+ struct device_attribute *devattr, const char *buf, -+ size_t count) ++static struct clk_hw *ast2700_clk_hw_register_pll(int clk_idx, void __iomem *reg, ++ const char *name, const struct clk_hw *parent_hw, ++ struct ast2700_clk_ctrl *clk_ctrl) +{ -+ 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; ++ int scu = clk_ctrl->clk_data->scu; ++ unsigned int mult, div; ++ u32 val = readl(reg); + -+ foo[8] = 0; -+ memcpy(foo, buf, 8); -+ ret = kstrtouint(foo, 16, &tmp); -+ if (ret) -+ return ret; ++ if (val & BIT(24)) { ++ /* Pass through mode */ ++ mult = 1; ++ div = 1; ++ } else { ++ u32 m = val & 0x1fff; ++ u32 n = (val >> 13) & 0x3f; ++ u32 p = (val >> 19) & 0xf; + -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_MODE, tmp); ++ if (scu) { ++ mult = (m + 1) / (n + 1); ++ div = p + 1; ++ } else { ++ if (clk_idx == SCU0_CLK_MPLL) { ++ mult = m / (n + 1); ++ div = p + 1; ++ } else { ++ mult = (m + 1) / (2 * (n + 1)); ++ div = p + 1; ++ } ++ } ++ } + -+ return count; ++ return devm_clk_hw_register_fixed_factor_parent_hw(clk_ctrl->dev, name, ++ parent_hw, 0, mult, div); +} + -+static ssize_t smode_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) ++static struct clk_hw *ast2700_clk_hw_register_uartpll(void __iomem *reg, const char *name, ++ const struct clk_hw *parent_hw, ++ struct ast2700_clk_ctrl *clk_ctrl) +{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ unsigned int mult, div; ++ u32 val = readl(reg); ++ u32 r = val & 0xff; ++ u32 n = (val >> 8) & 0x3ff; + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_SMODE)); ++ mult = r; ++ div = n * 2; ++ ++ return devm_clk_hw_register_fixed_factor_parent_hw(clk_ctrl->dev, name, ++ parent_hw, 0, mult, div); +} + -+static ssize_t smode_reg_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) ++static struct clk_hw *ast2700_clk_hw_register_misc(int clk_idx, void __iomem *reg, ++ const char *name, const struct clk_hw *parent_hw, ++ struct ast2700_clk_ctrl *clk_ctrl) +{ -+ 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; ++ u32 div = 0; + -+ foo[8] = 0; -+ memcpy(foo, buf, 8); -+ ret = kstrtouint(foo, 16, &tmp); -+ if (ret) -+ return ret; ++ if (clk_idx == SCU0_CLK_MPHY) { ++ div = readl(reg) + 1; ++ } else if (clk_idx == SCU0_CLK_U2PHY_REFCLK) { ++ if (readl(clk_ctrl->base) & REVISION_ID) ++ div = (GET_USB_REFCLK_DIV(readl(reg)) + 1) << 4; ++ else ++ div = (GET_USB_REFCLK_DIV(readl(reg)) + 1) << 1; ++ } else { ++ return ERR_PTR(-EINVAL); ++ } + -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_SMODE, tmp); -+ return count; ++ return devm_clk_hw_register_fixed_factor_parent_hw(clk_ctrl->dev, name, ++ parent_hw, 0, 1, div); +} + -+static ssize_t alarm_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) ++static int ast2700_clk_is_enabled(struct clk_hw *hw) +{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ struct clk_gate *gate = to_clk_gate(hw); ++ u32 clk = BIT(gate->bit_idx); ++ u32 reg; + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_ALARM)); ++ reg = readl(gate->reg); ++ ++ return !(reg & clk); +} + -+static ssize_t alarm_reg_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) ++static int ast2700_clk_enable(struct clk_hw *hw) +{ -+ 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; ++ struct clk_gate *gate = to_clk_gate(hw); ++ u32 clk = BIT(gate->bit_idx); + -+ foo[8] = 0; -+ memcpy(foo, buf, 8); -+ ret = kstrtouint(foo, 16, &tmp); -+ if (ret) -+ return ret; ++ if (readl(gate->reg) & clk) ++ writel(clk, gate->reg + 0x04); + -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_ALARM, tmp); -+ return count; ++ return 0; +} + -+static ssize_t stat_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) ++static void ast2700_clk_disable(struct clk_hw *hw) +{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ struct clk_gate *gate = to_clk_gate(hw); ++ u32 clk = BIT(gate->bit_idx); + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_STAT)); ++ /* Clock is set to enable, so use write to set register */ ++ writel(clk, gate->reg); +} + -+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; ++static const struct clk_ops ast2700_clk_gate_ops = { ++ .enable = ast2700_clk_enable, ++ .disable = ast2700_clk_disable, ++ .is_enabled = ast2700_clk_is_enabled, ++}; + -+ foo[8] = 0; -+ memcpy(foo, buf, 8); -+ ret = kstrtouint(foo, 16, &tmp); -+ if (ret) -+ return ret; ++static struct clk_hw *ast2700_clk_hw_register_gate(struct device *dev, const char *name, ++ const struct clk_hw *parent_hw, ++ void __iomem *reg, u8 clock_idx, ++ unsigned long flags, spinlock_t *lock) ++{ ++ struct clk_init_data init; ++ struct clk_gate *gate; ++ struct clk_hw *hw; ++ int ret = -EINVAL; + -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_WDATA, tmp); -+ return count; -+} ++ gate = kzalloc(sizeof(*gate), GFP_KERNEL); ++ if (!gate) ++ return ERR_PTR(-ENOMEM); + -+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); ++ init.name = name; ++ init.ops = &ast2700_clk_gate_ops; ++ init.flags = flags; ++ init.parent_names = NULL; ++ init.parent_hws = parent_hw ? &parent_hw : NULL; ++ init.parent_data = NULL; ++ init.num_parents = parent_hw ? 1 : 0; + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_IA_WDATA)); -+} ++ gate->reg = reg; ++ gate->bit_idx = clock_idx; ++ gate->flags = 0; ++ gate->lock = lock; ++ gate->hw.init = &init; + -+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); ++ hw = &gate->hw; ++ ret = clk_hw_register(dev, hw); ++ if (ret) { ++ kfree(gate); ++ hw = ERR_PTR(ret); ++ } + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_IA_RDATA)); ++ return hw; +} + -+static ssize_t ia_addr_reg_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) ++static void ast2700_soc1_configure_mac01_clk(struct ast2700_clk_ctrl *clk_ctrl) +{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char foo[9]; -+ unsigned int tmp; ++ struct device_node *np = clk_ctrl->dev->of_node; ++ struct mac_delay_config mac_cfg; ++ u32 reg[3]; + 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; ++ 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; + -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_ADDR, tmp); -+ return count; -+} ++ 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); + -+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); ++ 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); + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_IA_ADDR)); -+} ++ 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); ++ } + -+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; ++ 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); + -+ // string must be at least a 32-bit word in 0 padded hex -+ if (count < 8) -+ return -1; ++ 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); + -+ foo[8] = 0; -+ memcpy(foo, buf, 8); -+ ret = kstrtouint(foo, 16, &tmp); -+ if (ret) -+ return ret; ++ 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); ++ } + -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_REG_IA_CMD, tmp); -+ return count; ++ 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 ssize_t ia_cmd_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) ++static void ast2700_soc1_configure_i3c_clk(struct ast2700_clk_ctrl *clk_ctrl) +{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ if (readl(clk_ctrl->base) & REVISION_ID) { ++ u32 val; + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_REG_IA_CMD)); ++ /* I3C 250MHz = HPLL/4 */ ++ val = readl(clk_ctrl->base + SCU1_CLK_SEL2) & ~SCU1_CLK_I3C_DIV_MASK; ++ val |= FIELD_PREP(SCU1_CLK_I3C_DIV_MASK, SCU1_CLK_I3C_DIV(4)); ++ writel(val, clk_ctrl->base + SCU1_CLK_SEL2); ++ } +} + -+static ssize_t rnc_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) ++static inline const struct clk_hw *get_parent_hw_or_null(struct clk_hw **hws, int idx) +{ -+ 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)); ++ if (idx < 0) ++ return NULL; ++ else ++ return hws[idx]; +} + -+static ssize_t rnc_reg_store(struct device *dev, -+ struct device_attribute *devattr, const char *buf, -+ size_t count) ++static int ast2700_soc_clk_probe(struct platform_device *pdev) +{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char foo[9]; -+ unsigned int tmp; ++ const struct ast2700_clk_data *clk_data; ++ struct clk_hw_onecell_data *clk_hw_data; ++ struct ast2700_clk_ctrl *clk_ctrl; ++ struct device *dev = &pdev->dev; ++ u32 uart_clk_source = 0; ++ void __iomem *clk_base; ++ struct clk_hw **hws; ++ char *reset_name; + int ret; ++ int i; + -+ // string must be at least a 32-bit word in 0 padded hex -+ if (count < 8) -+ return -1; ++ clk_ctrl = devm_kzalloc(dev, sizeof(*clk_ctrl), GFP_KERNEL); ++ if (!clk_ctrl) ++ return -ENOMEM; ++ clk_ctrl->dev = dev; ++ dev_set_drvdata(&pdev->dev, clk_ctrl); + -+ foo[8] = 0; -+ memcpy(foo, buf, 8); -+ ret = kstrtouint(foo, 16, &tmp); -+ if (ret) -+ return ret; ++ spin_lock_init(&clk_ctrl->lock); + -+ pdu_io_write32(priv->nisttrng.base + NIST_TRNG_EDU_RNC_CTRL, tmp); ++ clk_base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(clk_base)) ++ return PTR_ERR(clk_base); + -+ return count; -+} ++ clk_ctrl->base = clk_base; + -+static ssize_t rbc_reg_show(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ clk_data = (struct ast2700_clk_data *)device_get_match_data(dev); ++ if (!clk_data) ++ return -ENODEV; + -+ return sprintf(buf, "%08lx\n", -+ pdu_io_read32(priv->nisttrng.base + NIST_TRNG_EDU_RBC_CTRL)); -+} ++ clk_ctrl->clk_data = clk_data; ++ reset_name = devm_kasprintf(dev, GFP_KERNEL, "reset%d", clk_data->scu); + -+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); ++ clk_hw_data = devm_kzalloc(dev, struct_size(clk_hw_data, hws, clk_data->nr_clks), ++ GFP_KERNEL); ++ if (!clk_hw_data) ++ return -ENOMEM; + -+ opts_str[4] = 0; -+ memcpy(opts_str, buf, 4); -+ ret = kstrtouint(opts_str, 16, &opts_int); -+ if (ret) -+ return ret; ++ clk_hw_data->num = clk_data->nr_clks; ++ hws = clk_hw_data->hws; + -+ SYNHW_PRINT("%s %x\n", __func__, opts_int); ++ if (clk_data->scu) { ++ of_property_read_u32(dev->of_node, "uart-clk-source", &uart_clk_source); ++ if (uart_clk_source) { ++ u32 val = readl(clk_base + SCU1_CLK_SEL1) & ~GENMASK(12, 0); + -+ enable = (opts_int >> 12 & 0xf); -+ if (enable > 1) { -+ SYNHW_PRINT("incorrect enable %x\n", enable); -+ return -1; -+ } ++ uart_clk_source &= GENMASK(12, 0); ++ writel(val | uart_clk_source, clk_base + SCU1_CLK_SEL1); ++ } + -+ 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; ++ ast2700_soc1_configure_mac01_clk(clk_ctrl); ++ ast2700_soc1_configure_i3c_clk(clk_ctrl); + } + -+ rate = (opts_int >> 4 & 0xf); -+ if (rate > 8) { -+ SYNHW_PRINT("incorrect rate %x\n", rate); -+ return -1; -+ } ++ for (i = 0; i < clk_data->nr_clks; i++) { ++ const struct ast2700_clk_info *clk = &clk_data->clk_info[i]; ++ const struct clk_hw *phw = NULL; ++ unsigned int id = clk->id; ++ void __iomem *reg = NULL; + -+ urun_blnk = (opts_int & 0xf); -+ if (urun_blnk > 3) { -+ SYNHW_PRINT("incorrect urun_blnk %x\n", urun_blnk); -+ return -1; -+ } ++ if (id >= clk_hw_data->num || hws[id]) { ++ dev_err(dev, "clk id %u invalid for %s\n", id, clk->name); ++ return -EINVAL; ++ } + -+ SYNHW_PRINT("enable %x rbc_num %x rate %x urun_blnk %x\n", enable, -+ rbc_num, rate, urun_blnk); ++ if (clk->type == CLK_FIXED) { ++ const struct ast2700_clk_fixed_rate_data *fixed_rate = &clk->data.rate; + -+ ret = nisttrng_rbc(&priv->nisttrng, enable, rbc_num, rate, -+ urun_blnk); -+ if (ret) -+ return -1; ++ hws[id] = devm_clk_hw_register_fixed_rate(dev, clk->name, NULL, 0, ++ fixed_rate->fixed_rate); ++ } else if (clk->type == CLK_FIXED_FACTOR) { ++ const struct ast2700_clk_fixed_factor_data *factor = &clk->data.factor; + -+ return count; -+} ++ phw = hws[factor->parent_id]; ++ hws[id] = devm_clk_hw_register_fixed_factor_parent_hw(dev, clk->name, ++ phw, 0, factor->mult, ++ factor->div); ++ } else if (clk->type == CLK_FIXED_DISPLAY) { ++ reg = clk_ctrl->base + clk->data.display_rate.reg; + -+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; ++ hws[id] = ast2700_clk_hw_register_fixed_display(reg, clk->name, clk_ctrl); ++ } else if (clk->type == CLK_HPLL) { ++ const struct ast2700_clk_pll_data *pll = &clk->data.pll; + -+ 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"); ++ reg = clk_ctrl->base + pll->reg; ++ phw = hws[pll->parent_id]; ++ hws[id] = ast2700_clk_hw_register_hpll(reg, clk->name, phw, clk_ctrl); ++ } else if (clk->type == CLK_PLL) { ++ const struct ast2700_clk_pll_data *pll = &clk->data.pll; + -+ 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)); -+ } ++ reg = clk_ctrl->base + pll->reg; ++ phw = hws[pll->parent_id]; ++ hws[id] = ast2700_clk_hw_register_pll(id, reg, clk->name, phw, clk_ctrl); ++ } else if (clk->type == CLK_UART_PLL) { ++ const struct ast2700_clk_pll_data *pll = &clk->data.pll; + -+ tot_char += sprintf(buf + tot_char, "\n"); ++ reg = clk_ctrl->base + pll->reg; ++ phw = hws[pll->parent_id]; ++ hws[id] = ast2700_clk_hw_register_uartpll(reg, clk->name, phw, clk_ctrl); ++ } else if (clk->type == CLK_MUX) { ++ const struct ast2700_clk_mux_data *mux = &clk->data.mux; + -+ return tot_char; -+} ++ reg = clk_ctrl->base + mux->reg; ++ for (int j = 0; j < mux->num_parents; j++) { ++ unsigned int pid = mux->parent_ids[j]; + -+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; ++ mux->parent_hws[j] = hws[pid]; ++ } + -+ // string must be at least a 32-bit word in 0 padded hex -+ if (count < 8) -+ return -1; ++ hws[id] = devm_clk_hw_register_mux_parent_hws(dev, clk->name, ++ mux->parent_hws, ++ mux->num_parents, 0, ++ reg, mux->bit_shift, ++ mux->bit_width, 0, ++ &clk_ctrl->lock); ++ } else if (clk->type == CLK_MISC) { ++ const struct ast2700_clk_pll_data *pll = &clk->data.pll; + -+ foo[8] = 0; -+ memcpy(foo, buf, 8); -+ ret = kstrtoul(foo, 16, &tmp); -+ if (ret) -+ return ret; ++ reg = clk_ctrl->base + pll->reg; ++ phw = hws[pll->parent_id]; ++ hws[id] = ast2700_clk_hw_register_misc(id, reg, clk->name, phw, clk_ctrl); ++ } else if (clk->type == CLK_DIVIDER) { ++ const struct ast2700_clk_div_data *divider = &clk->data.div; + -+ ret = nisttrng_set_reminder_max_bits_per_req(&priv->nisttrng, -+ tmp); ++ reg = clk_ctrl->base + divider->reg; ++ phw = hws[divider->parent_id]; ++ hws[id] = clk_hw_register_divider_table_parent_hw(dev, clk->name, ++ phw, ++ 0, reg, ++ divider->bit_shift, ++ divider->bit_width, 0, ++ divider->div_table, ++ &clk_ctrl->lock); ++ } else if (clk->type == CLK_GATE_ASPEED) { ++ const struct ast2700_clk_gate_data *gate = &clk->data.gate; ++ ++ phw = get_parent_hw_or_null(hws, gate->parent_id); ++ reg = clk_ctrl->base + gate->reg; ++ hws[id] = ast2700_clk_hw_register_gate(dev, clk->name, phw, reg, gate->bit, ++ gate->flags, &clk_ctrl->lock); ++ } else { ++ const struct ast2700_clk_gate_data *gate = &clk->data.gate; ++ ++ phw = get_parent_hw_or_null(hws, gate->parent_id); ++ reg = clk_ctrl->base + gate->reg; ++ hws[id] = devm_clk_hw_register_gate_parent_hw(dev, clk->name, phw, ++ gate->flags, reg, gate->bit, ++ 0, &clk_ctrl->lock); ++ } ++ ++ if (IS_ERR(hws[id])) ++ return PTR_ERR(hws[id]); ++ } ++ ++ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_hw_data); + if (ret) -+ return -1; ++ return ret; + -+ return count; ++ return aspeed_reset_controller_register(dev, clk_base, reset_name); +} + -+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); ++static const struct ast2700_clk_data ast2700_clk0_data = { ++ .scu = 0, ++ .clk_info = ast2700_scu0_clk_info, ++ .nr_clks = ARRAY_SIZE(ast2700_scu0_clk_info), ++}; + -+ return sprintf(buf, "%08lx\n", -+ priv->nisttrng.counters.max_bits_per_req); -+} ++static const struct ast2700_clk_data ast2700_clk1_data = { ++ .scu = 1, ++ .clk_info = ast2700_scu1_clk_info, ++ .nr_clks = ARRAY_SIZE(ast2700_scu1_clk_info), ++}; + -+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; ++static const struct ast2700_clk_data ast2755_clk1_data = { ++ .scu = 2, ++ .clk_info = ast2755_scu1_clk_info, ++ .nr_clks = ARRAY_SIZE(ast2755_scu1_clk_info), ++}; + -+ // string must be at least a 64-bit word in 0 padded hex -+ if (count < 16) -+ return -1; ++static const struct of_device_id ast2700_scu_match[] = { ++ { .compatible = "aspeed,ast2700-scu0", .data = &ast2700_clk0_data }, ++ { .compatible = "aspeed,ast2700-scu1", .data = &ast2700_clk1_data }, ++ { .compatible = "aspeed,ast2755-scu1", .data = &ast2755_clk1_data }, ++ { /* sentinel */ } ++}; + -+ foo[16] = 0; -+ memcpy(foo, buf, 16); -+ ret = kstrtoull(foo, 16, &tmp); -+ if (ret) -+ return ret; ++MODULE_DEVICE_TABLE(of, ast2700_scu_match); + -+ ret = nisttrng_set_reminder_max_req_per_seed(&priv->nisttrng, -+ tmp); -+ if (ret) -+ return -1; ++static struct platform_driver ast2700_scu_driver = { ++ .probe = ast2700_soc_clk_probe, ++ .driver = { ++ .name = "clk-ast2700", ++ .of_match_table = ast2700_scu_match, ++ }, ++}; + -+ return count; ++static int __init clk_ast2700_init(void) ++{ ++ return platform_driver_register(&ast2700_scu_driver); +} ++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 +@@ -1,26 +1,32 @@ + config CRYPTO_DEV_ASPEED +- tristate "Support for Aspeed cryptographic engine driver" ++ bool "Support for Aspeed cryptographic engine driver" + depends on ARCH_ASPEED || COMPILE_TEST + select CRYPTO_ENGINE + help +- Hash and Crypto Engine (HACE) is designed to accelerate the +- throughput of hash data digest, encryption and decryption. ++ Say Y here to get to see options for Aspeed hardware crypto devices + +- Select y here to have support for the cryptographic driver +- available on Aspeed SoC. ++if CRYPTO_DEV_ASPEED + + config CRYPTO_DEV_ASPEED_DEBUG + bool "Enable Aspeed crypto debug messages" +- depends on CRYPTO_DEV_ASPEED + help + Print Aspeed crypto debugging messages if you use this + option to ask for those messages. + Avoid enabling this option for production build to + minimize driver timing. + ++config CRYPTO_DEV_ASPEED_HACE ++ tristate "Enable Aspeed Hash & Crypto Engine (HACE) Engine" ++ help ++ Hash and Crypto Engine (HACE) is designed to accelerate the ++ throughput of hash data digest, encryption and decryption. + -+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); ++ Select y here to have support for the cryptographic driver ++ available on Aspeed SoC. + -+ return sprintf(buf, "%08llx\n", -+ priv->nisttrng.counters.max_req_per_seed); -+} + config CRYPTO_DEV_ASPEED_HACE_HASH + bool "Enable Aspeed Hash & Crypto Engine (HACE) hash" +- depends on CRYPTO_DEV_ASPEED ++ depends on CRYPTO_DEV_ASPEED_HACE + select CRYPTO_SHA1 + select CRYPTO_SHA256 + select CRYPTO_SHA512 +@@ -33,25 +39,56 @@ + + config CRYPTO_DEV_ASPEED_HACE_CRYPTO + bool "Enable Aspeed Hash & Crypto Engine (HACE) crypto" +- depends on CRYPTO_DEV_ASPEED ++ depends on CRYPTO_DEV_ASPEED_HACE + select CRYPTO_AES + select CRYPTO_DES + select CRYPTO_ECB + select CRYPTO_CBC ++ select CRYPTO_CFB ++ select CRYPTO_OFB + select CRYPTO_CTR + help + Select here to enable Aspeed Hash & Crypto Engine (HACE) + crypto driver. + Supports AES/DES symmetric-key encryption and decryption +- with ECB/CBC/CTR options. ++ with ECB/CBC/CFB/OFB/CTR options. + + config CRYPTO_DEV_ASPEED_ACRY +- bool "Enable Aspeed ACRY RSA Engine" +- depends on CRYPTO_DEV_ASPEED +- select CRYPTO_ENGINE ++ tristate "Enable Aspeed ACRY RSA Engine" ++ depends on MACH_ASPEED_G6 + select CRYPTO_RSA + help + Select here to enable Aspeed ECC/RSA Engine (ACRY) + RSA driver. + Supports 256 bits to 4096 bits RSA encryption/decryption + and signature/verification. + -+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; ++config CRYPTO_DEV_ASPEED_RSSS ++ tristate "Enable Aspeed RSSS Engine" ++ depends on ARCH_ASPEED ++ select CRYPTO_RSA ++ select CRYPTO_SHA3 ++ select CRYPTO_SM3 ++ select CRYPTO_SM4 ++ help ++ Select here to enable Aspeed RSSS Engine driver. ++ Supports RSA 512 to 4096 bits encryption/decryption and ++ signature/verification, SHA3-224/256/384/512 and XOF of ++ SHAKE 128/256, SM3 Hash crypto, SM4 ECB/CBC/CFB/OFB/CTR ++ cryptographic algorithms. ++ It's a new hardware design from ast2700 for simply SRAM ++ layout. + -+ t = NIST_TRNG_RETRY_MAX; ++config CRYPTO_DEV_ASPEED_ECDSA ++ tristate "Enable Aspeed ECDSA Engine" ++ depends on ARCH_ASPEED ++ select CRYPTO_ECC ++ select CRYPTO_ECDSA ++ select CRYPTO_AKCIPHER ++ help ++ Select here to enable Aspeed ECC Engine for ECDSA driver. ++ Supports ECDSA (Elliptic Curve Digital Signature Algorithm) ++ using curves P-256, P-384. ++ Only signature verification is implemented. + -+ // 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); ++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 +@@ -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 + +-obj-$(CONFIG_CRYPTO_DEV_ASPEED) += aspeed_crypto.o ++obj-$(CONFIG_CRYPTO_DEV_ASPEED_HACE) += aspeed_crypto.o + aspeed_crypto-objs := aspeed-hace.o \ + $(hace-hash-y) \ + $(hace-crypto-y) + +-aspeed_acry-$(CONFIG_CRYPTO_DEV_ASPEED_ACRY) += aspeed-acry.o ++obj-$(CONFIG_CRYPTO_DEV_ASPEED_ACRY) += aspeed-acry.o + +-obj-$(CONFIG_CRYPTO_DEV_ASPEED) += $(aspeed_acry-y) ++obj-$(CONFIG_CRYPTO_DEV_ASPEED_RSSS) += aspeed_rsss.o ++aspeed_rsss-objs := aspeed-rsss.o aspeed-rsss-rsa.o aspeed-rsss-hash.o + -+ // 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); ++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 @@ + + static struct platform_driver aspeed_acry_driver = { + .probe = aspeed_acry_probe, +- .remove_new = aspeed_acry_remove, ++ .remove = aspeed_acry_remove, + .driver = { + .name = KBUILD_MODNAME, + .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 +@@ -0,0 +1,779 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright 2023 Aspeed Technology Inc. ++ */ + -+ // 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; ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ 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); ++#include "aspeed-ecdsa.h" + -+ 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)); -+ } ++//#define ASPEED_ECDSA_IRQ_MODE + -+ // clear NOISE_RDY IRQ -+ DEBUG("Clear NOISE_RDY interrupt.\n"); -+ ret = nisttrng_wait_on_noise_rdy(&priv->nisttrng); -+ if (ret) -+ return -1; -+ } ++static int aspeed_ecdsa_self_test(struct aspeed_ecdsa_dev *ecdsa_dev) ++{ ++ u32 val; + -+ DEBUG("Wait for DONE\n"); -+ ret = nisttrng_wait_on_done(&priv->nisttrng); -+ if (ret) -+ return -1; ++ ast_write(ecdsa_dev, ECC_EN, ASPEED_ECC_CTRL_REG); ++ val = ast_read(ecdsa_dev, ASPEED_ECC_CTRL_REG); ++ if (val != ECC_EN) ++ return -EIO; + -+ strcat(buf, "\n"); -+ return strlen(buf); ++ ast_write(ecdsa_dev, 0x0, ASPEED_ECC_CTRL_REG); ++ val = ast_read(ecdsa_dev, ASPEED_ECC_CTRL_REG); ++ if (val) ++ return -EIO; ++ ++ return 0; +} + -+static ssize_t collect_ent_nsout_show(struct device *dev, -+ struct device_attribute *devattr, -+ char *buf) ++static inline struct akcipher_request * ++ akcipher_request_cast(struct crypto_async_request *req) +{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ int rep; -+ int i; -+ int ret; ++ return container_of(req, struct akcipher_request, base); ++} + -+ // generate entropy -+ ret = nisttrng_get_entropy_input(&priv->nisttrng, NULL, 0); -+ if (ret) -+ return -1; ++#ifdef CONFIG_CRYPTO_DEV_ASPEED_DEBUG ++static void hexdump(const char *name, unsigned char *buf, unsigned int len) ++{ ++ pr_info("%s\n", name); ++ print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET, ++ 16, 1, ++ buf, len, false); ++} ++#else ++static void hexdump(const char *name, unsigned char *buf, unsigned int len) ++{ ++ /* empty */ ++} ++#endif + -+ // 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; ++static void buff_reverse(u8 *dst, u8 *src, int len) ++{ ++ for (int i = 0; i < len; i++) ++ dst[len - i - 1] = src[i]; ++} + -+ 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)); ++static bool aspeed_ecdsa_need_fallback(struct aspeed_ecc_ctx *ctx, int d_len) ++{ ++ int curve_id = ctx->curve_id; ++ ++ switch (curve_id) { ++ case ECC_CURVE_NIST_P256: ++ if (d_len != SHA256_DIGEST_SIZE) ++ return true; ++ break; ++ case ECC_CURVE_NIST_P384: ++ if (d_len != SHA384_DIGEST_SIZE) ++ return true; ++ break; + } + -+ strcat(buf, "\n"); -+ return strlen(buf); ++ return false; +} + -+static ssize_t nonce_seed_with_df_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) ++#ifndef ASPEED_ECDSA_IRQ_MODE ++static int aspeed_ecdsa_wait_complete(struct aspeed_ecdsa_dev *ecdsa_dev) +{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char foo[9]; -+ u32 seed[48] = { 0 }; -+ int rep; -+ int i; ++ struct aspeed_engine_ecdsa *ecdsa_engine = &ecdsa_dev->ecdsa_engine; ++ u32 sts; + 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; ++ ret = readl_poll_timeout(ecdsa_dev->regs + ASPEED_ECC_STS_REG, sts, ++ ((sts & ECC_IDLE) == ECC_IDLE), ++ ASPEED_ECC_POLLING_TIME, ++ ASPEED_ECC_TIMEOUT * 10); ++ if (ret) { ++ dev_err(ecdsa_dev->dev, "ECC engine wrong status\n"); ++ return -EIO; ++ } + -+ DEBUG("Number of char in input = %zu\n", count); -+ if (count != (rep * 128)) -+ return -1; ++ sts = ast_read(ecdsa_dev, ASPEED_ECC_STS_REG) & ECC_VERIFY_PASS; ++ if (sts == ECC_VERIFY_PASS) { ++ ecdsa_engine->results = 0; ++ AST_DBG(ecdsa_dev, "Verify PASS !\n"); + -+ 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; ++ } else { ++ ecdsa_engine->results = -EKEYREJECTED; ++ AST_DBG(ecdsa_dev, "Verify FAILED !\n"); + } + -+ ret = nisttrng_get_entropy_input(&priv->nisttrng, seed, 1); -+ if (ret) -+ return -1; ++ /* Stop ECDSA engine */ ++ if (ecdsa_engine->flags & CRYPTO_FLAGS_BUSY) ++ tasklet_schedule(&ecdsa_engine->done_task); ++ else ++ dev_err(ecdsa_dev->dev, "ECDSA no active requests.\n"); + -+ return count; ++ return ecdsa_engine->results; +} ++#endif + -+static ssize_t nonce_seed_direct_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) ++static int aspeed_hw_trigger(struct aspeed_ecdsa_dev *ecdsa_dev) +{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ char foo[9]; -+ u32 seed[12] = { 0 }; -+ int rep; -+ int i; -+ int ret; ++ AST_DBG(ecdsa_dev, "\n"); + -+ if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES128) -+ rep = 2; -+ else if (priv->nisttrng.status.sec_strength == SEC_STRNT_AES256) -+ rep = 3; ++ ast_write(ecdsa_dev, 0x1, ASPEED_ECC_ECDSA_VERIFY); + -+ DEBUG("Number of char in input = %zu\n", count); -+ if (count != (rep * 32)) -+ return -1; ++ ast_write(ecdsa_dev, ECC_EN, ASPEED_ECC_CMD_REG); ++ ast_write(ecdsa_dev, 0x0, ASPEED_ECC_CMD_REG); + -+ 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; ++#ifdef ASPEED_ECDSA_IRQ_MODE ++ return 0; ++#else ++ return aspeed_ecdsa_wait_complete(ecdsa_dev); ++#endif +} + -+static ssize_t instantiate_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) ++static int _aspeed_ecdsa_verify(struct aspeed_ecc_ctx *ctx, const u64 *hash, ++ const u64 *r, const u64 *s) +{ -+ 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; -+ } ++ int nbytes = ctx->curve->g.ndigits << ECC_DIGITS_TO_BYTES_SHIFT; ++ const struct ecc_curve *curve = ctx->curve; ++ void __iomem *base = ctx->ecdsa_dev->regs; ++ unsigned int ndigits = curve->g.ndigits; ++ u8 *data, *buf; + -+ if (opts_int & 1) -+ ps_exists = 1; -+ else -+ ps_exists = 0; ++ /* 0 < r < n and 0 < s < n */ ++ if (vli_is_zero(r, ndigits) || vli_cmp(r, curve->n, ndigits) >= 0 || ++ vli_is_zero(s, ndigits) || vli_cmp(s, curve->n, ndigits) >= 0) ++ return -EBADMSG; + -+ if (opts_int & 2) -+ req_sec_strength = 256; -+ else -+ req_sec_strength = 128; ++ /* hash is given */ ++ AST_DBG(ctx->ecdsa_dev, "hash : %016llx %016llx ... %016llx\n", ++ hash[ndigits - 1], hash[ndigits - 2], hash[0]); + -+ if (opts_int & 4) -+ pred_resist = 1; -+ else -+ pred_resist = 0; ++ data = vmalloc(nbytes); ++ if (!data) ++ return -ENOMEM; + -+ /* 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; -+ } -+ } ++ /* Initial signature/message and trigger ecdsa verification */ ++ buf = (u8 *)r; ++ hexdump("Dump r:", buf, nbytes); + -+ /* Personilization string */ -+ for (i = 0; i < 12; i++) -+ ps[i] = 0; ++ buff_reverse(data, (u8 *)r, nbytes); ++ memcpy_toio(base + ASPEED_ECC_SIGN_R_REG, data, nbytes); + -+ if (req_sec_strength == 128) -+ ps_length = 64; -+ else if (req_sec_strength == 256) -+ ps_length = 96; -+ else -+ SYNHW_PRINT("Invalid security strength\n"); ++ buf = (u8 *)s; ++ hexdump("Dump s:", buf, nbytes); + -+ if (ps_exists) { -+ opts_str[1] = 0; -+ memcpy(opts_str, buf + 3, 1); ++ buff_reverse(data, (u8 *)s, nbytes); ++ memcpy_toio(base + ASPEED_ECC_SIGN_S_REG, data, nbytes); + -+ 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"); -+ } ++ buf = (u8 *)hash; ++ hexdump("Dump m:", buf, nbytes); + -+ ret = nisttrng_instantiate(&priv->nisttrng, -+ req_sec_strength, pred_resist, -+ ps); -+ if (ret) -+ return -1; ++ buff_reverse(data, (u8 *)hash, nbytes); ++ memcpy_toio(base + ASPEED_ECC_MESSAGE_REG, data, nbytes); + -+ } else { -+ ret = nisttrng_instantiate(&priv->nisttrng, -+ req_sec_strength, pred_resist, -+ NULL); -+ if (ret) -+ return -1; -+ } ++ vfree(data); + -+ return count; ++ return aspeed_hw_trigger(ctx->ecdsa_dev); +} + -+static ssize_t uninstantiate_store(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) ++static int aspeed_ecdsa_handle_queue(struct aspeed_ecdsa_dev *ecdsa_dev, ++ struct akcipher_request *req) +{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); ++ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); ++ struct aspeed_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); ++ int ret; + -+ nisttrng_uninstantiate(&priv->nisttrng); ++ if (aspeed_ecdsa_need_fallback(ctx, req->dst_len)) { ++ AST_DBG(ctx->ecdsa_dev, "SW fallback\n"); + -+ return count; ++ akcipher_request_set_tfm(req, ctx->fallback_tfm); ++ ret = crypto_akcipher_verify(req); ++ akcipher_request_set_tfm(req, tfm); ++ ++ AST_DBG(ctx->ecdsa_dev, "SW verify...ret:0x%x\n", ret); ++ ++ return ret; ++ } ++ ++ return crypto_transfer_akcipher_request_to_engine(ecdsa_dev->crypt_engine_ecdsa, req); +} + -+static ssize_t reseed_store(struct device *dev, struct device_attribute *devattr, -+ const char *buf, size_t count) ++static int aspeed_ecdsa_trigger(struct aspeed_ecdsa_dev *ecdsa_dev) +{ -+ 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; ++ struct aspeed_engine_ecdsa *ecdsa_engine = &ecdsa_dev->ecdsa_engine; ++ struct akcipher_request *req = ecdsa_engine->req; ++ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); ++ struct aspeed_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); ++ size_t keylen = ctx->curve->g.ndigits * sizeof(u64); ++ struct ecdsa_signature_ctx sig_ctx = { ++ .curve = ctx->curve, ++ }; ++ u8 rawhash[ECC_MAX_BYTES]; ++ u64 hash[ECC_MAX_DIGITS]; ++ unsigned char *buffer; ++ ssize_t diff; + 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; ++ AST_DBG(ecdsa_dev, "\n"); + -+ 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 (unlikely(!ctx->pub_key_set)) ++ return -EINVAL; + -+ if (opts_int & 1) -+ addin_exists = 1; -+ else -+ addin_exists = 0; ++ buffer = kmalloc(req->src_len + req->dst_len, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; + -+ if (opts_int & 2) -+ pred_resist = 1; -+ else -+ pred_resist = 0; ++ /* Input src: signature + digest */ ++ sg_pcopy_to_buffer(req->src, sg_nents_for_len(req->src, req->src_len + req->dst_len), ++ buffer, req->src_len + req->dst_len, 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; -+ } ++ ret = asn1_ber_decoder(&ecdsasignature_decoder, &sig_ctx, ++ buffer, req->src_len); ++ if (ret < 0) ++ goto error; ++ ++ /* if the hash is shorter then we will add leading zeros to fit to ndigits */ ++ diff = keylen - req->dst_len; ++ if (diff >= 0) { ++ if (diff) ++ memset(rawhash, 0, diff); ++ memcpy(&rawhash[diff], buffer + req->src_len, req->dst_len); ++ } else if (diff < 0) { ++ /* given hash is longer, we take the left-most bytes */ ++ memcpy(&rawhash, buffer + req->src_len, keylen); + } + -+ /* Additional input */ -+ for (i = 0; i < 12; i++) -+ addin[i] = 0; ++ ecc_swap_digits((u64 *)rawhash, hash, ctx->curve->g.ndigits); + -+ 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"); ++ ret = _aspeed_ecdsa_verify(ctx, hash, sig_ctx.r, sig_ctx.s); + -+ if (addin_exists) { -+ opts_str[1] = 0; -+ memcpy(opts_str, buf + 2, 1); ++error: ++ kfree(buffer); + -+ 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"); -+ } ++ return ret; ++} + -+ ret = nisttrng_reseed(&priv->nisttrng, pred_resist, -+ addin); -+ if (ret) -+ return -1; ++/* ++ * Verify an ECDSA signature. ++ */ ++static int aspeed_ecdsa_verify(struct akcipher_request *req) ++{ ++ struct crypto_akcipher *cipher = crypto_akcipher_reqtfm(req); ++ struct aspeed_ecc_ctx *ctx = akcipher_tfm_ctx(cipher); ++ struct aspeed_ecdsa_dev *ecdsa_dev = ctx->ecdsa_dev; + -+ } else { -+ ret = nisttrng_reseed(&priv->nisttrng, pred_resist, -+ NULL); -+ if (ret) -+ return -1; -+ } ++ AST_DBG(ecdsa_dev, "\n"); + -+ return count; ++ ctx->trigger = aspeed_ecdsa_trigger; ++ ++ return aspeed_ecdsa_handle_queue(ecdsa_dev, req); +} + -+static ssize_t generate_store(struct device *dev, -+ struct device_attribute *devattr, const char *buf, -+ size_t count) ++static int aspeed_ecdsa_ecc_ctx_init(struct aspeed_ecc_ctx *ctx, unsigned int curve_id) +{ -+ 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; ++ void __iomem *base = ctx->ecdsa_dev->regs; ++ u8 *data, *buf; ++ u32 ctrl; ++ int nbytes; + -+ 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; -+ } ++ ctx->curve_id = curve_id; ++ ctx->curve = ecc_get_curve(curve_id); ++ if (!ctx->curve) ++ return -EINVAL; + -+ if (opts_int & 1) -+ addin_exists = 1; -+ else -+ addin_exists = 0; ++ nbytes = ctx->curve->g.ndigits << ECC_DIGITS_TO_BYTES_SHIFT; + -+ if (opts_int & 2) -+ req_sec_strength = 256; -+ else -+ req_sec_strength = 128; ++ switch (curve_id) { ++ case ECC_CURVE_NIST_P256: ++ AST_DBG(ctx->ecdsa_dev, "curve ECC_CURVE_NIST_P256\n"); ++ ctrl = ECDSA_256_EN; ++ break; ++ case ECC_CURVE_NIST_P384: ++ AST_DBG(ctx->ecdsa_dev, "curve ECC_CURVE_NIST_P384\n"); ++ ctrl = ECDSA_384_EN; ++ break; ++ } + -+ if (opts_int & 4) -+ pred_resist = 1; -+ else -+ pred_resist = 0; ++ mutex_lock(&ctx->ecdsa_dev->lock); + -+ /* 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; -+ } -+ } ++ ast_write(ctx->ecdsa_dev, ECC_EN | ctrl, ASPEED_ECC_CTRL_REG); + -+ /* Additional input */ -+ for (i = 0; i < 12; i++) -+ addin[i] = 0; ++ /* Initial Curve: ecc point/p/a/n */ ++ data = vmalloc(nbytes); ++ if (!data) ++ return -ENOMEM; + -+ if (req_sec_strength == 128) -+ addin_length = 64; -+ else if (req_sec_strength == 256) -+ addin_length = 96; -+ else -+ SYNHW_PRINT("Invalid security strength\n"); ++ buf = (u8 *)ctx->curve->g.x; ++ hexdump("Dump Gx:", buf, nbytes); + -+ if (addin_exists) { -+ opts_str[1] = 0; -+ memcpy(opts_str, buf + 3, 1); ++ buff_reverse(data, (u8 *)ctx->curve->g.x, nbytes); ++ memcpy_toio(base + ASPEED_ECC_PAR_GX_REG, data, nbytes); + -+ 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"); -+ } ++ buf = (u8 *)ctx->curve->g.y; ++ hexdump("Dump Gy:", buf, nbytes); + -+ ret = nisttrng_generate(&priv->nisttrng, (u32 *)out, -+ num_gen_bytes, req_sec_strength, -+ pred_resist, addin); -+ if (ret) -+ return -1; ++ buff_reverse(data, (u8 *)ctx->curve->g.y, nbytes); ++ memcpy_toio(base + ASPEED_ECC_PAR_GY_REG, data, nbytes); + -+ } else { -+ ret = nisttrng_generate(&priv->nisttrng, (u32 *)out, -+ num_gen_bytes, req_sec_strength, -+ pred_resist, NULL); -+ if (ret) -+ return -1; -+ } ++ buf = (u8 *)ctx->curve->p; ++ hexdump("Dump P:", buf, nbytes); + -+ /* store the result */ -+ memcpy(priv->rand_out, out, sizeof(out)); ++ buff_reverse(data, (u8 *)ctx->curve->p, nbytes); ++ memcpy_toio(base + ASPEED_ECC_PAR_P_REG, data, nbytes); + -+ return count; -+} ++ buf = (u8 *)ctx->curve->a; ++ hexdump("Dump A:", buf, nbytes); + -+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; ++ buff_reverse(data, (u8 *)ctx->curve->a, nbytes); ++ memcpy_toio(base + ASPEED_ECC_PAR_A_REG, data, nbytes); + -+ opts_str[1] = 0; -+ memcpy(opts_str, buf, 1); -+ ret = kstrtouint(opts_str, 16, &opts_int); -+ if (ret) -+ return ret; ++ buf = (u8 *)ctx->curve->n; ++ hexdump("Dump N:", buf, nbytes); + -+ 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); ++ buff_reverse(data, (u8 *)ctx->curve->n, nbytes); ++ memcpy_toio(base + ASPEED_ECC_PAR_N_REG, data, nbytes); + -+ ret = nisttrng_generate_public_vtrng(&priv->nisttrng, -+ (u32 *)out, -+ num_gen_bytes, opts_int); -+ if (ret) -+ return -1; ++ vfree(data); ++ return 0; ++} + -+ memcpy(priv->rand_out, out, sizeof(out)); ++static void aspeed_ecdsa_ecc_ctx_deinit(struct aspeed_ecc_ctx *ctx) ++{ ++ mutex_unlock(&ctx->ecdsa_dev->lock); + -+ return count; ++ ctx->pub_key_set = false; +} + -+/* 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) ++static void aspeed_ecdsa_ecc_ctx_reset(struct aspeed_ecc_ctx *ctx) +{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ unsigned int i, j; -+ unsigned long rand; -+ bool all_zero = true; ++ ctx->pub_key = ECC_POINT_INIT(ctx->x, ctx->y, ++ ctx->curve->g.ndigits); ++} + -+ /* 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; -+ } -+ } ++/* ++ * Set the public key given the raw uncompressed key data from an X509 ++ * certificate. The key data contain the concatenated X and Y coordinates of ++ * the public key. ++ */ ++static int aspeed_ecdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, ++ unsigned int keylen) ++{ ++ struct aspeed_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); ++ int nbytes = ctx->curve->g.ndigits << ECC_DIGITS_TO_BYTES_SHIFT; ++ void __iomem *base = ctx->ecdsa_dev->regs; ++ const unsigned char *d = key; ++ const u64 *digits = (const u64 *)&d[1]; ++ unsigned int ndigits; ++ u8 *data, *buf; ++ int ret; + -+ 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++; -+ } -+ } ++ AST_DBG(ctx->ecdsa_dev, "\n"); + -+ strcat(buf, "\n"); -+ return strlen(buf); -+} ++ ret = crypto_akcipher_set_pub_key(ctx->fallback_tfm, key, keylen); ++ if (ret) ++ return ret; + -+/* 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; ++ aspeed_ecdsa_ecc_ctx_reset(ctx); + -+ /* If all bits of the rand_reg register are 0, display 0 */ ++ if (keylen < 1 || (((keylen - 1) >> 1) % sizeof(u64)) != 0) ++ return -EINVAL; ++ /* we only accept uncompressed format indicated by '4' */ ++ if (d[0] != 4) ++ return -EINVAL; + -+ 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]); -+ } -+ } ++ keylen--; ++ ndigits = (keylen >> 1) / sizeof(u64); ++ if (ndigits != ctx->curve->g.ndigits) ++ return -EINVAL; + -+ 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++; -+ } ++ ecc_swap_digits(digits, ctx->pub_key.x, ndigits); ++ ecc_swap_digits(&digits[ndigits], ctx->pub_key.y, ndigits); ++ ret = ecc_is_pubkey_valid_full(ctx->curve, &ctx->pub_key); + -+ strcat(buf, "\n"); -+ return strlen(buf); ++ /* Set public key: Qx/Qy */ ++ data = vmalloc(nbytes); ++ if (!data) ++ return -ENOMEM; ++ ++ buf = (u8 *)ctx->pub_key.x; ++ hexdump("Dump Qx:", buf, nbytes); ++ ++ buff_reverse(data, (u8 *)ctx->pub_key.x, nbytes); ++ memcpy_toio(base + ASPEED_ECC_PAR_QX_REG, data, nbytes); ++ ++ buf = (u8 *)ctx->pub_key.y; ++ hexdump("Dump Qy:", buf, nbytes); ++ ++ buff_reverse(data, (u8 *)ctx->pub_key.y, nbytes); ++ memcpy_toio(base + ASPEED_ECC_PAR_QY_REG, data, nbytes); ++ ++ ctx->pub_key_set = ret == 0; ++ ++ vfree(data); ++ ++ return ret; +} + -+static ssize_t kat_store(struct device *dev, struct device_attribute *devattr, -+ const char *buf, size_t count) ++static void aspeed_ecdsa_exit_tfm(struct crypto_akcipher *tfm) +{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ int ret; ++ struct aspeed_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + -+ if (sysfs_streq(buf, "full")) { -+ ret = nisttrng_full_kat(&priv->nisttrng); -+ if (ret) -+ return -1; ++ AST_DBG(ctx->ecdsa_dev, "\n"); + -+ } else if (sysfs_streq(buf, "00")) { -+ ret = nisttrng_kat(&priv->nisttrng, 0, 0); -+ if (ret) -+ return -1; ++ aspeed_ecdsa_ecc_ctx_deinit(ctx); + -+ } else if (sysfs_streq(buf, "01")) { -+ ret = nisttrng_kat(&priv->nisttrng, 0, 1); -+ if (ret) -+ return -1; ++ crypto_free_akcipher(ctx->fallback_tfm); ++} + -+ } else if (sysfs_streq(buf, "10")) { -+ ret = nisttrng_kat(&priv->nisttrng, 1, 0); -+ if (ret) -+ return -1; ++static unsigned int aspeed_ecdsa_max_size(struct crypto_akcipher *tfm) ++{ ++ struct aspeed_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + -+ } else if (sysfs_streq(buf, "11")) { -+ ret = nisttrng_kat(&priv->nisttrng, 1, 1); -+ if (ret) -+ return -1; ++ return ctx->pub_key.ndigits << ECC_DIGITS_TO_BYTES_SHIFT; ++} + -+ } else { -+ ret = nisttrng_full_kat(&priv->nisttrng); -+ if (ret) -+ return -1; ++static int aspeed_ecdsa_nist_p384_init_tfm(struct crypto_akcipher *tfm) ++{ ++ struct aspeed_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); ++ struct akcipher_alg *alg = crypto_akcipher_alg(tfm); ++ const char *name = crypto_tfm_alg_name(&tfm->base); ++ struct aspeed_ecdsa_alg *ecdsa_alg; ++ ++ ecdsa_alg = container_of(alg, struct aspeed_ecdsa_alg, akcipher.base); ++ ++ ctx->ecdsa_dev = ecdsa_alg->ecdsa_dev; ++ ++ AST_DBG(ctx->ecdsa_dev, "\n"); ++ ctx->fallback_tfm = crypto_alloc_akcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK); ++ if (IS_ERR(ctx->fallback_tfm)) { ++ dev_err(ctx->ecdsa_dev->dev, "ERROR: Cannot allocate fallback for %s %ld\n", ++ name, PTR_ERR(ctx->fallback_tfm)); ++ return PTR_ERR(ctx->fallback_tfm); + } + -+ return count; ++ return aspeed_ecdsa_ecc_ctx_init(ctx, ECC_CURVE_NIST_P384); +} + -+static void str_to_384_bit(char *buf, u32 *out) ++static int aspeed_ecdsa_nist_p256_init_tfm(struct crypto_akcipher *tfm) +{ -+ char foo[9]; -+ int i; -+ int ret; ++ struct aspeed_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); ++ struct akcipher_alg *alg = crypto_akcipher_alg(tfm); ++ const char *name = crypto_tfm_alg_name(&tfm->base); ++ struct aspeed_ecdsa_alg *ecdsa_alg; + -+ foo[8] = 0; -+ for (i = 0; i < 12; i++) { -+ memcpy(foo, buf + i * 8, 8); -+ ret = kstrtouint(foo, 16, out + 11 - i); ++ ecdsa_alg = container_of(alg, struct aspeed_ecdsa_alg, akcipher.base); ++ ++ ctx->ecdsa_dev = ecdsa_alg->ecdsa_dev; ++ ++ AST_DBG(ctx->ecdsa_dev, "\n"); ++ ctx->fallback_tfm = crypto_alloc_akcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK); ++ if (IS_ERR(ctx->fallback_tfm)) { ++ dev_err(ctx->ecdsa_dev->dev, "ERROR: Cannot allocate fallback for %s %ld\n", ++ name, PTR_ERR(ctx->fallback_tfm)); ++ return PTR_ERR(ctx->fallback_tfm); + } ++ ++ return aspeed_ecdsa_ecc_ctx_init(ctx, ECC_CURVE_NIST_P256); +} + -+/* 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) ++static int aspeed_ecdsa_complete(struct aspeed_ecdsa_dev *ecdsa_dev) +{ -+ struct synopsys_nisttrng_driver *priv = dev_get_drvdata(dev); -+ int i; -+ int err; -+ u32 addin[12]; -+ u32 ps[12]; -+ char *out; ++ struct aspeed_engine_ecdsa *ecdsa_engine = &ecdsa_dev->ecdsa_engine; ++ struct akcipher_request *req = ecdsa_engine->req; ++ int results = ecdsa_engine->results; + -+ 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]; ++ AST_DBG(ecdsa_dev, "\n"); + -+ for (i = 0; i < 12; i++) -+ addin[i] = i; ++ ecdsa_engine->flags &= ~CRYPTO_FLAGS_BUSY; + -+ for (i = 0; i < 12; i++) -+ ps[i] = i + 100; ++ crypto_finalize_akcipher_request(ecdsa_dev->crypt_engine_ecdsa, req, results); + -+ /* SDK doc example - Prediction Resistance not available, no Reseed */ -+ err = nisttrng_uninstantiate(&priv->nisttrng); -+ if (err && err != CRYPTO_NOT_INSTANTIATED) -+ return -1; ++ return results; ++} + -+ if (nisttrng_instantiate(&priv->nisttrng, 128, 0, ps) < 0) -+ return -1; ++static int aspeed_ecdsa_do_request(struct crypto_engine *engine, void *areq) ++{ ++ struct akcipher_request *req = akcipher_request_cast(areq); ++ struct crypto_akcipher *cipher = crypto_akcipher_reqtfm(req); ++ struct aspeed_ecc_ctx *ctx = akcipher_tfm_ctx(cipher); ++ struct aspeed_ecdsa_dev *ecdsa_dev = ctx->ecdsa_dev; ++ struct aspeed_engine_ecdsa *ecdsa_engine; + -+ out = kmalloc(10, GFP_KERNEL); -+ if (nisttrng_generate(&priv->nisttrng, out, 10, 128, 0, addin) < 0) -+ return -1; ++ AST_DBG(ctx->ecdsa_dev, "\n"); + -+ DEBUG("----- Generate 10 bytes\n"); -+ for (i = 0; i < 10; i++) -+ DEBUG("%02x", out[i]); ++ ecdsa_engine = &ecdsa_dev->ecdsa_engine; ++ ecdsa_engine->req = req; ++ ecdsa_engine->flags |= CRYPTO_FLAGS_BUSY; ++ ecdsa_engine->resume = aspeed_ecdsa_complete; + -+ DEBUG("\n"); -+ kfree(out); ++ return ctx->trigger(ecdsa_dev); ++} + -+ out = kmalloc(512, GFP_KERNEL); -+ if (nisttrng_generate(&priv->nisttrng, out, 512, 128, 0, addin) < 0) -+ return -1; ++static void aspeed_ecdsa_done_task(unsigned long data) ++{ ++ struct aspeed_ecdsa_dev *ecdsa_dev = (struct aspeed_ecdsa_dev *)data; ++ struct aspeed_engine_ecdsa *ecdsa_engine = &ecdsa_dev->ecdsa_engine; ++ u32 ctrl; + -+ DEBUG("----- Generate 512 bytes\n"); -+ for (i = 0; i < 512; i++) -+ DEBUG("%02x", out[i]); ++ AST_DBG(ecdsa_dev, "\n"); + -+ DEBUG("\n"); -+ kfree(out); ++ /* Reset engine */ ++ ctrl = ast_read(ecdsa_dev, ASPEED_ECC_CTRL_REG); ++ ast_write(ecdsa_dev, 0, ASPEED_ECC_CTRL_REG); + -+ out = kmalloc(41, GFP_KERNEL); -+ if (nisttrng_generate(&priv->nisttrng, out, 41, 128, 0, addin) < 0) -+ return -1; ++ /* Memory barrier to ensure ecc ctrl is reset. */ ++ mb(); ++ ast_write(ecdsa_dev, ctrl, ASPEED_ECC_CTRL_REG); + -+ DEBUG("----- Generate 41 bytes\n"); -+ for (i = 0; i < 41; i++) -+ DEBUG("%02x", out[i]); ++ (void)ecdsa_engine->resume(ecdsa_dev); ++} + -+ DEBUG("\n"); -+ kfree(out); ++static struct aspeed_ecdsa_alg aspeed_ecdsa_nist_p256 = { ++ .akcipher.base = { ++ .verify = aspeed_ecdsa_verify, ++ .set_pub_key = aspeed_ecdsa_set_pub_key, ++ .max_size = aspeed_ecdsa_max_size, ++ .init = aspeed_ecdsa_nist_p256_init_tfm, ++ .exit = aspeed_ecdsa_exit_tfm, ++ .base = { ++ .cra_name = "ecdsa-nist-p256", ++ .cra_driver_name = "aspeed-ecdsa-nist-p256", ++ .cra_priority = 300, ++ .cra_module = THIS_MODULE, ++ .cra_ctxsize = sizeof(struct aspeed_ecc_ctx), ++ .cra_flags = CRYPTO_ALG_TYPE_AKCIPHER | ++ CRYPTO_ALG_KERN_DRIVER_ONLY | ++ CRYPTO_ALG_NEED_FALLBACK, ++ }, ++ }, ++ .akcipher.op = { ++ .do_one_request = aspeed_ecdsa_do_request, ++ }, ++}; + -+ err = nisttrng_uninstantiate(&priv->nisttrng); -+ if (err < 0 && err != CRYPTO_NOT_INSTANTIATED) -+ return -1; ++static struct aspeed_ecdsa_alg aspeed_ecdsa_nist_p384 = { ++ .akcipher.base = { ++ .verify = aspeed_ecdsa_verify, ++ .set_pub_key = aspeed_ecdsa_set_pub_key, ++ .max_size = aspeed_ecdsa_max_size, ++ .init = aspeed_ecdsa_nist_p384_init_tfm, ++ .exit = aspeed_ecdsa_exit_tfm, ++ .base = { ++ .cra_name = "ecdsa-nist-p384", ++ .cra_driver_name = "aspeed-ecdsa-nist-p384", ++ .cra_priority = 300, ++ .cra_module = THIS_MODULE, ++ .cra_ctxsize = sizeof(struct aspeed_ecc_ctx), ++ .cra_flags = CRYPTO_ALG_TYPE_AKCIPHER | ++ CRYPTO_ALG_KERN_DRIVER_ONLY | ++ CRYPTO_ALG_NEED_FALLBACK, ++ }, ++ }, ++ .akcipher.op = { ++ .do_one_request = aspeed_ecdsa_do_request, ++ }, ++}; + -+ /* SDK doc example - DRBG Validation */ -+ err = nisttrng_uninstantiate(&priv->nisttrng); -+ if (err && err != CRYPTO_NOT_INSTANTIATED) -+ return -1; ++static int aspeed_ecdsa_register(struct aspeed_ecdsa_dev *ecdsa_dev) ++{ ++ int rc; + -+ if (nisttrng_set_nonce_mode(&priv->nisttrng, 1) < 0) -+ return -1; ++ aspeed_ecdsa_nist_p256.ecdsa_dev = ecdsa_dev; ++ rc = crypto_engine_register_akcipher(&aspeed_ecdsa_nist_p256.akcipher); ++ if (rc) ++ goto nist_p256_error; + -+ out = kmalloc(64, GFP_KERNEL); -+ str_to_384_bit(buf_seed1, tmp); -+ if (nisttrng_get_entropy_input(&priv->nisttrng, tmp, 0) < 0) -+ return -1; ++ aspeed_ecdsa_nist_p384.ecdsa_dev = ecdsa_dev; ++ rc = crypto_engine_register_akcipher(&aspeed_ecdsa_nist_p384.akcipher); ++ if (rc) ++ goto nist_p384_error; + -+ str_to_384_bit(buf_ps1, tmp); -+ if (nisttrng_instantiate(&priv->nisttrng, 256, 1, tmp) < 0) -+ return -1; ++ return 0; + -+ str_to_384_bit(buf_seed2, tmp); -+ if (nisttrng_get_entropy_input(&priv->nisttrng, tmp, 0) < 0) -+ return -1; ++nist_p384_error: ++ crypto_engine_unregister_akcipher(&aspeed_ecdsa_nist_p256.akcipher); + -+ str_to_384_bit(buf_addin1, tmp); -+ if (nisttrng_generate(&priv->nisttrng, out, 64, 256, 1, tmp) < 0) -+ return -1; ++nist_p256_error: ++ return rc; ++} + -+ str_to_384_bit(buf_seed3, tmp); -+ if (nisttrng_get_entropy_input(&priv->nisttrng, tmp, 0) < 0) -+ return -1; ++static void aspeed_ecdsa_unregister(struct aspeed_ecdsa_dev *ecdsa_dev) ++{ ++ crypto_engine_unregister_akcipher(&aspeed_ecdsa_nist_p256.akcipher); ++ crypto_engine_unregister_akcipher(&aspeed_ecdsa_nist_p384.akcipher); ++} + -+ str_to_384_bit(buf_addin2, tmp); -+ if (nisttrng_generate(&priv->nisttrng, out, 64, 256, 1, tmp) < 0) -+ return -1; ++#ifdef ASPEED_ECDSA_IRQ_MODE ++/* ecdsa interrupt service routine. */ ++static irqreturn_t aspeed_ecdsa_irq(int irq, void *dev) ++{ ++ struct aspeed_ecdsa_dev *ecdsa_dev = (struct aspeed_ecdsa_dev *)dev; ++ struct aspeed_engine_ecdsa *ecdsa_engine = &ecdsa_dev->ecdsa_engine; ++ u32 sts; + -+ memcpy(priv->rand_out, out, 64); ++ sts = ast_read(ecdsa_dev, ASPEED_ECC_INT_STS); ++ ast_write(ecdsa_dev, sts, ASPEED_ECC_INT_STS); + -+ return count; -+} ++ AST_DBG(ecdsa_dev, "irq sts:0x%x\n", sts); + -+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); ++ sts = ast_read(ecdsa_dev, ASPEED_ECC_STS_REG) & ECC_VERIFY_PASS; ++ if (sts == ECC_VERIFY_PASS) { ++ AST_DBG(ecdsa_dev, "Verify PASS !\n"); + -+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); ++ ecdsa_engine->results = 0; ++ /* Stop ECDSA engine */ ++ if (ecdsa_engine->flags & CRYPTO_FLAGS_BUSY) ++ tasklet_schedule(&ecdsa_engine->done_task); ++ else ++ dev_err(ecdsa_dev->dev, "ECDSA no active requests.\n"); + -+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); ++ } else { ++ ecdsa_engine->results = -EKEYREJECTED; ++ AST_DBG(ecdsa_dev, "Verify FAILED !\n"); ++ } + -+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); ++ return IRQ_HANDLED; ++} ++#endif + -+static DEVICE_ATTR_RW(max_bits_per_req); -+static DEVICE_ATTR_RW(max_req_per_seed); ++static const struct of_device_id aspeed_ecdsa_of_matches[] = { ++ { .compatible = "aspeed,ast2700-ecdsa", }, ++ {}, ++}; + -+static DEVICE_ATTR_WO(test_attr); ++static int aspeed_ecdsa_probe(struct platform_device *pdev) ++{ ++ struct aspeed_engine_ecdsa *ecdsa_engine; ++ struct aspeed_ecdsa_dev *ecdsa_dev; ++ struct device *dev = &pdev->dev; ++ int rc; + -+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, ++ ecdsa_dev = devm_kzalloc(dev, sizeof(struct aspeed_ecdsa_dev), ++ GFP_KERNEL); ++ if (!ecdsa_dev) ++ return -ENOMEM; + -+ &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, ++ ecdsa_dev->dev = dev; + -+ &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, ++ platform_set_drvdata(pdev, ecdsa_dev); + -+ &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, ++ ecdsa_dev->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(ecdsa_dev->regs)) ++ return PTR_ERR(ecdsa_dev->regs); + -+ &dev_attr_max_bits_per_req.attr, -+ &dev_attr_max_req_per_seed.attr, ++#ifdef ASPEED_ECDSA_IRQ_MODE ++ /* Get irq number and register it */ ++ ecdsa_dev->irq = platform_get_irq(pdev, 0); ++ if (ecdsa_dev->irq < 0) ++ return -ENXIO; + -+ &dev_attr_test_attr.attr, NULL }, -+}; ++ rc = devm_request_irq(dev, ecdsa_dev->irq, aspeed_ecdsa_irq, 0, ++ dev_name(dev), ecdsa_dev); ++ if (rc) { ++ dev_err(dev, "Failed to request irq.\n"); ++ return rc; ++ } + -+static int nisttrng_self_test(struct nist_trng_state *nist_trng) -+{ -+ u32 seed[16], out[4], x, y; ++ /* Enable interrupt */ ++ ast_write(ecdsa_dev, 0x1, ASPEED_ECC_INT_EN); ++#endif + -+ 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; ++ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); ++ if (rc) { ++ dev_warn(&pdev->dev, "No suitable DMA available\n"); ++ return rc; ++ } + -+ if (nist_trng->config.build_cfg0.edu_present) { -+ ret = nisttrng_wait_fifo_full(nist_trng); -+ if (ret) -+ goto ERR; ++ ecdsa_dev->clk = devm_clk_get_enabled(dev, NULL); ++ if (IS_ERR(ecdsa_dev->clk)) { ++ dev_err(dev, "Failed to get ecdsa clk\n"); ++ return PTR_ERR(ecdsa_dev->clk); + } + -+ ret = nisttrng_generate(nist_trng, out, 16, 128, 0, NULL); -+ if (ret) -+ goto ERR; ++ ecdsa_dev->rst = devm_reset_control_get_shared(dev, NULL); ++ if (IS_ERR(ecdsa_dev->rst)) { ++ dev_err(dev, "Failed to get ecdsa reset\n"); ++ return PTR_ERR(ecdsa_dev->rst); ++ } + -+ 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]); ++ rc = reset_control_deassert(ecdsa_dev->rst); ++ if (rc) { ++ dev_err(dev, "Deassert ecdsa reset failed\n"); ++ return rc; ++ } + -+ 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; -+ } -+ } ++ ecdsa_engine = &ecdsa_dev->ecdsa_engine; + -+ if (ret) { -+ SYNHW_PRINT("... FAILED comparison\n"); -+ ret = -1; -+ goto ERR; -+ } else { -+ DEBUG("... PASSED\n"); -+ } ++ /* Initialize crypto hardware engine structure for ECDSA */ ++ ecdsa_dev->crypt_engine_ecdsa = crypto_engine_alloc_init(ecdsa_dev->dev, true); ++ if (!ecdsa_dev->crypt_engine_ecdsa) { ++ rc = -ENOMEM; ++ goto end; + } + -+ // 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; ++ rc = crypto_engine_start(ecdsa_dev->crypt_engine_ecdsa); ++ if (rc) ++ goto err_engine_ecdsa_start; + -+ 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; ++ tasklet_init(&ecdsa_engine->done_task, aspeed_ecdsa_done_task, ++ (unsigned long)ecdsa_dev); + -+ tmp = pdu_io_read32(nist_trng->base + -+ NIST_TRNG_EDU_STAT); ++ /* Self-test */ ++ rc = aspeed_ecdsa_self_test(ecdsa_dev); ++ if (rc) ++ goto err_engine_ecdsa_start; + -+ } while (!NIST_TRNG_EDU_STAT_FIFO_EMPTY(tmp)); ++ rc = aspeed_ecdsa_register(ecdsa_dev); ++ if (rc) { ++ dev_err(dev, "ECDSA algo register failed\n"); ++ return rc; + } + -+ 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; ++ mutex_init(&ecdsa_dev->lock); + -+ ret = nisttrng_set_nonce_mode(nist_trng, 1); -+ if (ret) -+ goto ERR; ++ dev_info(dev, "Aspeed ECDSA Hardware Accelerator successfully registered\n"); + -+ ret = nisttrng_set_sec_strength(nist_trng, 256); -+ if (ret) -+ goto ERR; ++ return 0; + -+ ret = nisttrng_get_entropy_input(nist_trng, seed, 0); -+ if (ret) -+ goto ERR; ++err_engine_ecdsa_start: ++ crypto_engine_exit(ecdsa_dev->crypt_engine_ecdsa); ++end: ++ return rc; ++} + -+ ret = nisttrng_instantiate(nist_trng, 256, 0, NULL); -+ if (ret) -+ goto ERR; ++static void aspeed_ecdsa_remove(struct platform_device *pdev) ++{ ++ struct aspeed_ecdsa_dev *ecdsa_dev = platform_get_drvdata(pdev); + -+ ret = nisttrng_generate(nist_trng, out, 16, 256, 0, NULL); -+ if (ret) -+ goto ERR; ++ aspeed_ecdsa_unregister(ecdsa_dev); ++} + -+ 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]); ++MODULE_DEVICE_TABLE(of, aspeed_ecdsa_of_matches); + -+ 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"); -+ } -+ } -+ } ++static struct platform_driver aspeed_ecdsa_driver = { ++ .probe = aspeed_ecdsa_probe, ++ .remove = aspeed_ecdsa_remove, ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = aspeed_ecdsa_of_matches, ++ }, ++}; + -+ // 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; ++module_platform_driver(aspeed_ecdsa_driver); ++MODULE_AUTHOR("Neal Liu "); ++MODULE_DESCRIPTION("ASPEED ECDSA algorithm driver acceleration"); ++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 +@@ -0,0 +1,119 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ + -+ 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"); -+ } -+ } ++#ifndef __ASPEED_ECDSA_H__ ++#define __ASPEED_ECDSA_H__ + -+ //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; ++#ifdef CONFIG_CRYPTO_DEV_ASPEED_DEBUG ++#define AST_DBG(d, fmt, ...) \ ++ dev_info((d)->dev, "%s() " fmt, __func__, ##__VA_ARGS__) ++#else ++#define AST_DBG(d, fmt, ...) \ ++ dev_dbg((d)->dev, "%s() " fmt, __func__, ##__VA_ARGS__) ++#endif + -+ tmp = pdu_io_read32(nist_trng->base + -+ NIST_TRNG_EDU_RBC_CTRL); ++/************************* ++ * * ++ * ECDSA regs definition * ++ * * ++ *************************/ ++#define ASPEED_ECC_STS_REG 0xb0 ++#define ASPEED_ECC_CTRL_REG 0xb4 ++#define ASPEED_ECC_CMD_REG 0xbc ++#define ASPEED_ECC_INT_EN 0xc0 ++#define ASPEED_ECC_INT_STS 0xc4 + -+ 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"); -+ } ++#define ASPEED_ECC_DATA_BASE 0x800 ++#define ASPEED_ECC_PAR_GX_REG 0x800 ++#define ASPEED_ECC_PAR_GY_REG 0x840 ++#define ASPEED_ECC_PAR_QX_REG 0x880 ++#define ASPEED_ECC_PAR_QY_REG 0x8c0 ++#define ASPEED_ECC_PAR_P_REG 0x900 ++#define ASPEED_ECC_PAR_A_REG 0x940 ++#define ASPEED_ECC_PAR_N_REG 0x980 ++#define ASPEED_ECC_SIGN_R_REG 0x9c0 ++#define ASPEED_ECC_SIGN_S_REG 0xa00 ++#define ASPEED_ECC_MESSAGE_REG 0xa40 ++#define ASPEED_ECC_ECDSA_VERIFY 0xbc0 + -+ //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); -+ } ++/* sts */ ++#define ECC_IDLE BIT(0) ++#define ECC_VERIFY_PASS BIT(1) + -+ /* back to the noise mode */ -+ ret = nisttrng_set_nonce_mode(nist_trng, 0); -+ if (ret) -+ goto ERR; ++/* ctrl/cmd */ ++#define ECC_EN BIT(0) ++#define ECDSA_384_EN 0x0 ++#define ECDSA_256_EN BIT(1) ++#define ADDR_BE BIT(2) ++#define DATA_BE BIT(3) + -+ ret = nisttrng_zeroize(nist_trng); -+ if (ret) -+ goto ERR; -+ERR: -+ return ret; -+} ++#define PAR_LEN_256 32 ++#define PAR_LEN_384 48 + -+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; ++#define ASPEED_ECC_POLLING_TIME 100 ++#define ASPEED_ECC_TIMEOUT 100000 /* 100 ms */ + -+ // version -+ SYNHW_PRINT("DWC_TRNG_DriverSDK_%s\n", TRNG_VERSION); ++#define CRYPTO_FLAGS_BUSY BIT(1) + -+ cfg = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); ++#define ast_write(ast, val, offset) \ ++ writel((val), (ast)->regs + (offset)) + -+ if (!cfg || !irq) { -+ SYNHW_PRINT("no memory or IRQ resource\n"); -+ return -ENOMEM; -+ } ++#define ast_read(ast, offset) \ ++ readl((ast)->regs + (offset)) + -+ 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)); ++struct aspeed_ecdsa_dev; + -+ data = devm_kzalloc(&pdev->dev, sizeof(struct synopsys_nisttrng_driver), -+ GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; ++typedef int (*aspeed_ecdsa_fn_t)(struct aspeed_ecdsa_dev *); + -+ platform_set_drvdata(pdev, data); ++struct aspeed_ecc_ctx { ++ struct aspeed_ecdsa_dev *ecdsa_dev; ++ unsigned int curve_id; ++ const struct ecc_curve *curve; + -+ 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); -+ } ++ bool pub_key_set; ++ u64 x[ECC_MAX_DIGITS]; /* pub key x and y coordinates */ ++ u64 y[ECC_MAX_DIGITS]; ++ struct ecc_point pub_key; + -+ 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; -+ } ++ struct crypto_akcipher *fallback_tfm; + -+ /* 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; -+ } -+ } ++ aspeed_ecdsa_fn_t trigger; ++}; + -+ // issue quick self test -+ ret = nisttrng_self_test(&data->nisttrng); -+ if (ret) { -+ devm_kfree(&pdev->dev, data); -+ return -ENOMEM; -+ } ++struct ecdsa_signature_ctx { ++ const struct ecc_curve *curve; ++ u64 r[ECC_MAX_DIGITS]; ++ u64 s[ECC_MAX_DIGITS]; ++}; + -+ // 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; -+ } ++struct aspeed_engine_ecdsa { ++ struct tasklet_struct done_task; ++ unsigned long flags; ++ struct akcipher_request *req; ++ int results; + -+ // 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; -+ } ++ /* callback func */ ++ aspeed_ecdsa_fn_t resume; ++}; + -+ 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; -+ } ++struct aspeed_ecdsa_alg { ++ struct aspeed_ecdsa_dev *ecdsa_dev; ++ struct akcipher_engine_alg akcipher; ++}; + -+ 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)); ++struct aspeed_ecdsa_dev { ++ void __iomem *regs; ++ struct device *dev; ++ struct clk *clk; ++ struct reset_control *rst; ++ int irq; + -+ 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; ++ /* Support ecdsa256/384 execution concurrent */ ++ struct mutex lock; + -+ data->hwrng_drv = hwrng_driver_info; -+ ret = hwrng_register(hwrng_driver_info); ++ struct crypto_engine *crypt_engine_ecdsa; ++ struct aspeed_engine_ecdsa ecdsa_engine; ++}; + -+ 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; -+ } ++extern const struct asn1_decoder ecdsasignature_decoder; + -+ 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); -+} ++#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 @@ + 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 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 aspeed_crypto_do_fallback(struct skcipher_request *areq) + { + struct aspeed_cipher_reqctx *rctx = skcipher_request_ctx(areq); +@@ -143,6 +148,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); + } ++ up(&hace_dev->lock); + + return aspeed_sk_complete(hace_dev, 0); + } +@@ -206,10 +212,21 @@ + crypto_engine->resume = aspeed_sk_transfer; + + /* Trigger engines */ ++ ast_hace_write(hace_dev, crypto_engine->cipher_ctx_dma, ++ ASPEED_HACE_CONTEXT); + ast_hace_write(hace_dev, crypto_engine->cipher_dma_addr, + ASPEED_HACE_SRC); + ast_hace_write(hace_dev, crypto_engine->cipher_dma_addr, + ASPEED_HACE_DEST); ++#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT ++ 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->cipher_dma_addr >> 32, ++ ASPEED_HACE_DEST_H); ++#endif + -+static int __init nisttrng_platform_driver_start(void) -+{ -+ return platform_driver_register(&s_nisttrng_platform_driver_info); -+} + 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 @@ + struct aspeed_sg_list *src_list, *dst_list; + dma_addr_t src_dma_addr, dst_dma_addr; + struct aspeed_cipher_reqctx *rctx; ++ struct crypto_skcipher *cipher; ++ 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; + + CIPHER_DBG(hace_dev, "\n"); + + req = crypto_engine->req; ++ cipher = crypto_skcipher_reqtfm(req); ++ ctx = crypto_skcipher_ctx(cipher); + 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)); + -+static void __exit nisttrng_platform_driver_end(void) -+{ -+ platform_driver_unregister(&s_nisttrng_platform_driver_info); -+} ++ if (use_vault_key) ++ rctx->enc_cmd |= HACE_CMD_AES_KEY_FROM_OTP; ++ else ++ rctx->enc_cmd &= ~HACE_CMD_AES_KEY_FROM_OTP; ++ } + -+module_init(nisttrng_platform_driver_start); -+module_exit(nisttrng_platform_driver_end); + /* BIDIRECTIONAL */ + if (req->dst == req->src) { + src_sg_len = dma_map_sg(hace_dev->dev, req->src, +@@ -332,8 +393,19 @@ + mb(); + + /* Trigger engines */ ++ down(&hace_dev->lock); ++ ast_hace_write(hace_dev, crypto_engine->cipher_ctx_dma, ++ ASPEED_HACE_CONTEXT); + ast_hace_write(hace_dev, src_dma_addr, ASPEED_HACE_SRC); + ast_hace_write(hace_dev, dst_dma_addr, ASPEED_HACE_DEST); + -+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-04-08 18:03:46.630736014 +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. -+ */ ++#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT ++ ast_hace_write(hace_dev, crypto_engine->cipher_ctx_dma >> 32, ++ ASPEED_HACE_CONTEXT_H); ++ ast_hace_write(hace_dev, src_dma_addr >> 32, ASPEED_HACE_SRC_H); ++ ast_hace_write(hace_dev, dst_dma_addr >> 32, ASPEED_HACE_DEST_H); ++#endif + -+#include "nisttrng_hw.h" -+#include "nisttrng.h" + 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 @@ + rctx->dst_nents = sg_nents(req->dst); + rctx->src_nents = sg_nents(req->src); + +- ast_hace_write(hace_dev, crypto_engine->cipher_ctx_dma, +- ASPEED_HACE_CONTEXT); +- + 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 @@ + AES_BLOCK_SIZE); + } + +- if (hace_dev->version == AST2600_VERSION) { ++ if (hace_dev->version == AST2600_VERSION || ++ hace_dev->version == AST2700_VERSION) { + memcpy(crypto_engine->cipher_ctx + 16, ctx->key, ctx->key_len); + + return aspeed_sk_start_sg(hace_dev); +@@ -580,6 +650,8 @@ + + CIPHER_DBG(hace_dev, "keylen: %d bits\n", (keylen * 8)); + ++ ctx->dummy_key = find_dummy_key(key, keylen); + -+/* Initialize the NIST_TRNG state structure */ -+int nisttrng_init(struct nist_trng_state *state, u32 *base) + 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); + +- if (hace_dev->version != AST2600_VERSION) ++ if (hace_dev->version == AST2500_VERSION) + return; + + 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) +{ -+ int err; -+ u32 tmp; ++ struct aspeed_engine_crypto *crypto_engine = &hace_dev->crypto_engine; ++ u32 otp_data[16]; ++ int i; + -+ DEBUG(">> %s: initialize the NIST_TRNG\n", __func__); ++ crypto_engine->load_vault_key = 0; + -+ memset(state, 0, sizeof(*state)); ++ 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 (otp_data[i] & BIT(13)) ++ break; ++ } ++ CIPHER_DBG(hace_dev, "Not found vault key in OTP\n"); ++} ++#endif + -+ state->base = base; + void aspeed_register_hace_crypto_algs(struct aspeed_hace_dev *hace_dev) + { + int rc, i; + + CIPHER_DBG(hace_dev, "\n"); + ++#ifdef CONFIG_AST2600_OTP ++ find_vault_key(hace_dev); ++#else ++ hace_dev->crypto_engine.load_vault_key = 0; ++#endif + -+ /* make sure there is no alarm and the core is not busy */ -+ err = nisttrng_get_alarms(state); -+ if (err) -+ goto ERR; + 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 @@ + } + } + +- if (hace_dev->version != AST2600_VERSION) ++ if (hace_dev->version == AST2500_VERSION) + return; + + for (i = 0; i < ARRAY_SIZE(aspeed_crypto_algs_g6); i++) { +@@ -953,3 +1055,88 @@ + } + } + } + -+ err = nisttrng_wait_on_busy(state); -+ if (err) -+ goto ERR; ++static void aspeed_hace_crypto_done_task(unsigned long data) ++{ ++ struct aspeed_hace_dev *hace_dev = (struct aspeed_hace_dev *)data; ++ struct aspeed_engine_crypto *crypto_engine = &hace_dev->crypto_engine; + -+ /* hardware features*/ -+ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_FEATURES); ++ crypto_engine->resume(hace_dev); ++} + -+ 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); ++int aspeed_hace_crypto_init(struct aspeed_hace_dev *hace_dev) ++{ ++ struct aspeed_engine_crypto *crypto_engine; ++ int rc; + -+ /* 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); ++ crypto_engine = &hace_dev->crypto_engine; + -+ /* clear registers */ -+ pdu_io_write32(state->base + NIST_TRNG_REG_ALARM, 0xFFFFFFFF); -+ pdu_io_write32(state->base + NIST_TRNG_REG_ISTAT, 0xFFFFFFFF); ++ /* Initialize crypto hardware engine structure for crypto */ ++ hace_dev->crypt_engine_crypto = crypto_engine_alloc_init(hace_dev->dev, ++ true); ++ if (!hace_dev->crypt_engine_crypto) { ++ rc = -ENOMEM; ++ goto end; ++ } + -+ /* 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; ++ rc = crypto_engine_start(hace_dev->crypt_engine_crypto); ++ if (rc) ++ goto err_engine_crypto_start; + -+ } 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; ++ tasklet_init(&crypto_engine->done_task, aspeed_hace_crypto_done_task, ++ (unsigned long)hace_dev); + -+ } else { -+ SYNHW_PRINT("Invalid DRBG architecture"); -+ err = CRYPTO_FAILED; -+ goto ERR; ++ /* Allocate DMA buffer for crypto engine context used */ ++ crypto_engine->cipher_ctx = ++ dmam_alloc_coherent(hace_dev->dev, ++ PAGE_SIZE, ++ &crypto_engine->cipher_ctx_dma, ++ GFP_KERNEL); ++ if (!crypto_engine->cipher_ctx) { ++ dev_err(hace_dev->dev, "Failed to allocate cipher ctx dma\n"); ++ rc = -ENOMEM; ++ goto err_engine_crypto_start; + } + -+ 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); ++ /* Allocate DMA buffer for crypto engine input used */ ++ crypto_engine->cipher_addr = ++ dmam_alloc_coherent(hace_dev->dev, ++ ASPEED_CRYPTO_SRC_DMA_BUF_LEN, ++ &crypto_engine->cipher_dma_addr, ++ GFP_KERNEL); ++ if (!crypto_engine->cipher_addr) { ++ dev_err(hace_dev->dev, "Failed to allocate cipher addr dma\n"); ++ rc = -ENOMEM; ++ goto err_engine_crypto_start; ++ } + -+ /* 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; ++ /* Allocate DMA buffer for crypto engine output used */ ++ if (hace_dev->version == AST2600_VERSION || ++ hace_dev->version == AST2700_VERSION) { ++ crypto_engine->dst_sg_addr = ++ dmam_alloc_coherent(hace_dev->dev, ++ ASPEED_CRYPTO_DST_DMA_BUF_LEN, ++ &crypto_engine->dst_sg_dma_addr, ++ GFP_KERNEL); ++ if (!crypto_engine->dst_sg_addr) { ++ dev_err(hace_dev->dev, "Failed to allocate dst_sg dma\n"); ++ rc = -ENOMEM; ++ goto err_engine_crypto_start; ++ } + } + -+ DEBUG("initialization is done, going for a zeroize\n"); ++ return 0; + -+ // 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); ++err_engine_crypto_start: ++ crypto_engine_exit(hace_dev->crypt_engine_crypto); ++end: ++ return rc; ++} + -+ 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) ++void aspeed_hace_crypto_remove(struct aspeed_hace_dev *hace_dev) +{ -+ int err; -+ u32 tmp; -+ u32 zero_ps[12] = { 0 }; -+ int i = 0; ++ struct aspeed_engine_crypto *crypto_engine = &hace_dev->crypto_engine; + -+ DEBUG(">> %s: security strength = %u, pred_resist = %u, personilization string existence = %u\n", -+ __func__, req_sec_strength, pred_resist, (personal_str) ? 1 : 0); ++ crypto_engine_exit(hace_dev->crypt_engine_crypto); ++ tasklet_kill(&crypto_engine->done_task); ++} +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 +@@ -138,21 +138,13 @@ + return -EINVAL; + } + +- scatterwalk_map_and_copy(rctx->buffer, rctx->src_sg, +- rctx->offset, remain, 0); ++ scatterwalk_map_and_copy(rctx->buffer, rctx->src_sg, rctx->offset, ++ remain, 0); + + rctx->bufcnt = remain; +- rctx->digest_dma_addr = dma_map_single(hace_dev->dev, rctx->digest, +- SHA512_DIGEST_SIZE, +- DMA_BIDIRECTIONAL); +- if (dma_mapping_error(hace_dev->dev, rctx->digest_dma_addr)) { +- dev_warn(hace_dev->dev, "dma_map() rctx digest error\n"); +- return -ENOMEM; +- } + + hash_engine->src_length = length - remain; + hash_engine->src_dma = hash_engine->ahash_src_dma_addr; +- hash_engine->digest_dma = rctx->digest_dma_addr; + + return 0; + } +@@ -187,30 +179,12 @@ + } + + src_list = (struct aspeed_sg_list *)hash_engine->ahash_src_addr; +- rctx->digest_dma_addr = dma_map_single(hace_dev->dev, rctx->digest, +- SHA512_DIGEST_SIZE, +- DMA_BIDIRECTIONAL); +- if (dma_mapping_error(hace_dev->dev, rctx->digest_dma_addr)) { +- dev_warn(hace_dev->dev, "dma_map() rctx digest error\n"); +- rc = -ENOMEM; +- goto free_src_sg; +- } + + if (rctx->bufcnt != 0) { + u32 phy_addr; + u32 len; + +- rctx->buffer_dma_addr = dma_map_single(hace_dev->dev, +- rctx->buffer, +- rctx->block_size * 2, +- DMA_TO_DEVICE); +- if (dma_mapping_error(hace_dev->dev, rctx->buffer_dma_addr)) { +- dev_warn(hace_dev->dev, "dma_map() rctx buffer error\n"); +- rc = -ENOMEM; +- goto free_rctx_digest; +- } +- +- phy_addr = rctx->buffer_dma_addr; ++ phy_addr = hash_engine->buffer_dma_addr; + len = rctx->bufcnt; + length -= len; + +@@ -244,23 +218,15 @@ + + if (length != 0) { + rc = -EINVAL; +- goto free_rctx_buffer; ++ goto free_src_sg; + } + + rctx->offset = rctx->total - remain; + hash_engine->src_length = rctx->total + rctx->bufcnt - remain; + hash_engine->src_dma = hash_engine->ahash_src_dma_addr; +- hash_engine->digest_dma = rctx->digest_dma_addr; + + return 0; + +-free_rctx_buffer: +- if (rctx->bufcnt != 0) +- dma_unmap_single(hace_dev->dev, rctx->buffer_dma_addr, +- rctx->block_size * 2, DMA_TO_DEVICE); +-free_rctx_digest: +- dma_unmap_single(hace_dev->dev, rctx->digest_dma_addr, +- SHA512_DIGEST_SIZE, DMA_BIDIRECTIONAL); + free_src_sg: + dma_unmap_sg(hace_dev->dev, rctx->src_sg, rctx->src_nents, + DMA_TO_DEVICE); +@@ -294,13 +260,15 @@ + + AHASH_DBG(hace_dev, "\n"); + +- dma_unmap_single(hace_dev->dev, rctx->digest_dma_addr, +- SHA512_DIGEST_SIZE, DMA_BIDIRECTIONAL); +- +- dma_unmap_single(hace_dev->dev, rctx->buffer_dma_addr, +- rctx->block_size * 2, DMA_TO_DEVICE); ++ memcpy(req->result, hash_engine->digest_addr, rctx->digsize); + +- memcpy(req->result, rctx->digest, rctx->digsize); ++ /* ++ * Workaround for aes engine hang: The sha configuration may cause aes ++ * engine to hang. To address this issue, the hace engine is reset after ++ * the hash calculation is completed. ++ */ ++ aspeed_hace_reset(hace_dev); ++ up(&hace_dev->lock); + + return aspeed_ahash_complete(hace_dev); + } +@@ -315,13 +283,18 @@ + struct ahash_request *req = hash_engine->req; + struct aspeed_sham_reqctx *rctx = ahash_request_ctx(req); + ++ memcpy(hash_engine->digest_addr, rctx->digest, rctx->ivsize); ++ memcpy(hash_engine->buffer_addr, rctx->buffer, rctx->bufcnt); ++ hash_engine->digest_dma = hash_engine->digest_dma_addr; + -+ /* make sure there is no alarm and the core is not busy */ -+ err = nisttrng_get_alarms(state); -+ if (err) -+ goto ERR; + AHASH_DBG(hace_dev, "src_dma:%pad, digest_dma:%pad, length:%zu\n", + &hash_engine->src_dma, &hash_engine->digest_dma, + hash_engine->src_length); + +- rctx->cmd |= HASH_CMD_INT_ENABLE; ++ rctx->cmd |= HASH_CMD_INT_ENABLE | HASH_CMD_MBUS_REQ_SYNC_EN; + hash_engine->resume = resume; + ++ /* Trigger engines */ + ast_hace_write(hace_dev, hash_engine->src_dma, ASPEED_HACE_HASH_SRC); + ast_hace_write(hace_dev, hash_engine->digest_dma, + ASPEED_HACE_HASH_DIGEST_BUFF); +@@ -329,6 +302,14 @@ + ASPEED_HACE_HASH_KEY_BUFF); + ast_hace_write(hace_dev, hash_engine->src_length, + ASPEED_HACE_HASH_DATA_LEN); ++#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT ++ ast_hace_write(hace_dev, hash_engine->src_dma >> 32, ++ ASPEED_HACE_HASH_SRC_H); ++ ast_hace_write(hace_dev, hash_engine->digest_dma >> 32, ++ ASPEED_HACE_HASH_DIGEST_BUFF_H); ++ ast_hace_write(hace_dev, hash_engine->digest_dma >> 32, ++ ASPEED_HACE_HASH_KEY_BUFF_H); ++#endif + + /* Memory barrier to ensure all data setup before engine starts */ + mb(); +@@ -351,15 +332,10 @@ + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct aspeed_sham_ctx *tctx = crypto_ahash_ctx(tfm); + struct aspeed_sha_hmac_ctx *bctx = tctx->base; +- int rc = 0; + + AHASH_DBG(hace_dev, "\n"); + +- dma_unmap_single(hace_dev->dev, rctx->digest_dma_addr, +- SHA512_DIGEST_SIZE, DMA_BIDIRECTIONAL); +- +- dma_unmap_single(hace_dev->dev, rctx->buffer_dma_addr, +- rctx->block_size * 2, DMA_TO_DEVICE); ++ memcpy(rctx->digest, hash_engine->digest_addr, rctx->ivsize); + + /* o key pad + hash sum 1 */ + memcpy(rctx->buffer, bctx->opad, rctx->block_size); +@@ -371,35 +347,10 @@ + aspeed_ahash_fill_padding(hace_dev, rctx); + memcpy(rctx->digest, rctx->sha_iv, rctx->ivsize); + +- rctx->digest_dma_addr = dma_map_single(hace_dev->dev, rctx->digest, +- SHA512_DIGEST_SIZE, +- DMA_BIDIRECTIONAL); +- if (dma_mapping_error(hace_dev->dev, rctx->digest_dma_addr)) { +- dev_warn(hace_dev->dev, "dma_map() rctx digest error\n"); +- rc = -ENOMEM; +- goto end; +- } +- +- rctx->buffer_dma_addr = dma_map_single(hace_dev->dev, rctx->buffer, +- rctx->block_size * 2, +- DMA_TO_DEVICE); +- if (dma_mapping_error(hace_dev->dev, rctx->buffer_dma_addr)) { +- dev_warn(hace_dev->dev, "dma_map() rctx buffer error\n"); +- rc = -ENOMEM; +- goto free_rctx_digest; +- } +- +- hash_engine->src_dma = rctx->buffer_dma_addr; ++ hash_engine->src_dma = hash_engine->buffer_dma_addr; + hash_engine->src_length = rctx->bufcnt; +- hash_engine->digest_dma = rctx->digest_dma_addr; + + return aspeed_hace_ahash_trigger(hace_dev, aspeed_ahash_transfer); +- +-free_rctx_digest: +- dma_unmap_single(hace_dev->dev, rctx->digest_dma_addr, +- SHA512_DIGEST_SIZE, DMA_BIDIRECTIONAL); +-end: +- return rc; + } + + static int aspeed_ahash_req_final(struct aspeed_hace_dev *hace_dev) +@@ -407,47 +358,19 @@ + struct aspeed_engine_hash *hash_engine = &hace_dev->hash_engine; + struct ahash_request *req = hash_engine->req; + struct aspeed_sham_reqctx *rctx = ahash_request_ctx(req); +- int rc = 0; + + AHASH_DBG(hace_dev, "\n"); + + aspeed_ahash_fill_padding(hace_dev, rctx); + +- rctx->digest_dma_addr = dma_map_single(hace_dev->dev, +- rctx->digest, +- SHA512_DIGEST_SIZE, +- DMA_BIDIRECTIONAL); +- if (dma_mapping_error(hace_dev->dev, rctx->digest_dma_addr)) { +- dev_warn(hace_dev->dev, "dma_map() rctx digest error\n"); +- rc = -ENOMEM; +- goto end; +- } +- +- rctx->buffer_dma_addr = dma_map_single(hace_dev->dev, +- rctx->buffer, +- rctx->block_size * 2, +- DMA_TO_DEVICE); +- if (dma_mapping_error(hace_dev->dev, rctx->buffer_dma_addr)) { +- dev_warn(hace_dev->dev, "dma_map() rctx buffer error\n"); +- rc = -ENOMEM; +- goto free_rctx_digest; +- } +- +- hash_engine->src_dma = rctx->buffer_dma_addr; ++ hash_engine->src_dma = hash_engine->buffer_dma_addr; + hash_engine->src_length = rctx->bufcnt; +- hash_engine->digest_dma = rctx->digest_dma_addr; + + if (rctx->flags & SHA_FLAGS_HMAC) + return aspeed_hace_ahash_trigger(hace_dev, + aspeed_ahash_hmac_resume); + + return aspeed_hace_ahash_trigger(hace_dev, aspeed_ahash_transfer); +- +-free_rctx_digest: +- dma_unmap_single(hace_dev->dev, rctx->digest_dma_addr, +- SHA512_DIGEST_SIZE, DMA_BIDIRECTIONAL); +-end: +- return rc; + } + + static int aspeed_ahash_update_resume_sg(struct aspeed_hace_dev *hace_dev) +@@ -458,17 +381,11 @@ + + AHASH_DBG(hace_dev, "\n"); + ++ memcpy(rctx->digest, hash_engine->digest_addr, rctx->ivsize); + -+ err = nisttrng_wait_on_busy(state); -+ if (err) -+ goto ERR; + dma_unmap_sg(hace_dev->dev, rctx->src_sg, rctx->src_nents, + DMA_TO_DEVICE); + +- if (rctx->bufcnt != 0) +- dma_unmap_single(hace_dev->dev, rctx->buffer_dma_addr, +- rctx->block_size * 2, +- DMA_TO_DEVICE); +- +- dma_unmap_single(hace_dev->dev, rctx->digest_dma_addr, +- SHA512_DIGEST_SIZE, DMA_BIDIRECTIONAL); +- + scatterwalk_map_and_copy(rctx->buffer, rctx->src_sg, rctx->offset, + rctx->total - rctx->offset, 0); + +@@ -489,8 +406,7 @@ + + AHASH_DBG(hace_dev, "\n"); + +- dma_unmap_single(hace_dev->dev, rctx->digest_dma_addr, +- SHA512_DIGEST_SIZE, DMA_BIDIRECTIONAL); ++ memcpy(rctx->digest, hash_engine->digest_addr, rctx->ivsize); + + if (rctx->flags & SHA_FLAGS_FINUP) + return aspeed_ahash_req_final(hace_dev); +@@ -508,12 +424,12 @@ + + AHASH_DBG(hace_dev, "\n"); + +- if (hace_dev->version == AST2600_VERSION) { +- rctx->cmd |= HASH_CMD_HASH_SRC_SG_CTRL; +- resume = aspeed_ahash_update_resume_sg; ++ if (hace_dev->version == AST2500_VERSION) { ++ resume = aspeed_ahash_update_resume; + + } else { +- resume = aspeed_ahash_update_resume; ++ rctx->cmd |= HASH_CMD_HASH_SRC_SG_CTRL; ++ resume = aspeed_ahash_update_resume_sg; + } + + ret = hash_engine->dma_prepare(hace_dev); +@@ -526,8 +442,32 @@ + static int aspeed_hace_hash_handle_queue(struct aspeed_hace_dev *hace_dev, + struct ahash_request *req) + { +- return crypto_transfer_hash_request_to_engine( +- hace_dev->crypt_engine_hash, req); ++ struct aspeed_sham_reqctx *rctx = ahash_request_ctx(req); ++ struct aspeed_engine_hash *hash_engine = &hace_dev->hash_engine; ++ int ret = 0; ++ static bool init_req; + -+ /* 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; ++ /* The first request is enqueued, lock the queue */ ++ if (rctx->op & SHA_OP_INIT) { ++ mutex_lock(&hash_engine->queue_lock); ++ init_req = true; ++ return 0; + } + -+ /* 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; ++ /* The previous request is init request, enqueue the request with init flag */ ++ if (init_req) { ++ rctx->op |= SHA_OP_INIT; ++ init_req = false; + } + -+ /* Validate and set the security strength */ -+ err = nisttrng_set_sec_strength(state, req_sec_strength); -+ if (err) -+ goto ERR; ++ ret = crypto_transfer_hash_request_to_engine(hace_dev->crypt_engine_hash, ++ req); + -+ /* 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; -+ } ++ /* The last request is enqueued, release the lock */ ++ if (rctx->op & SHA_OP_FINAL || rctx->flags & SHA_FLAGS_FINUP) ++ mutex_unlock(&hash_engine->queue_lock); + -+ /* 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]; ++ return ret; + } + + static int aspeed_ahash_do_request(struct crypto_engine *engine, void *areq) +@@ -543,9 +483,14 @@ + hash_engine = &hace_dev->hash_engine; + hash_engine->flags |= CRYPTO_FLAGS_BUSY; + +- if (rctx->op == SHA_OP_UPDATE) ++ /* If the update/final is the first request, lock hace engine */ ++ if (rctx->op & SHA_OP_INIT) ++ down(&hace_dev->lock); + -+ err = nisttrng_load_ps_addin(state, personal_str); -+ if (err) -+ goto ERR; -+ } ++ /* Do the update/final operation no matter what */ ++ if (rctx->op & SHA_OP_UPDATE) + ret = aspeed_ahash_req_update(hace_dev); +- else if (rctx->op == SHA_OP_FINAL) ++ else if (rctx->op & SHA_OP_FINAL) + ret = aspeed_ahash_req_final(hace_dev); + + if (ret != -EINPROGRESS) +@@ -566,10 +511,10 @@ + hash_engine = &hace_dev->hash_engine; + hash_engine->req = req; + +- if (hace_dev->version == AST2600_VERSION) +- hash_engine->dma_prepare = aspeed_ahash_dma_prepare_sg; +- else ++ if (hace_dev->version == AST2500_VERSION) + hash_engine->dma_prepare = aspeed_ahash_dma_prepare; ++ else ++ hash_engine->dma_prepare = aspeed_ahash_dma_prepare_sg; + } + + static int aspeed_ahash_do_one(struct crypto_engine *engine, void *areq) +@@ -671,6 +616,7 @@ + crypto_ahash_digestsize(tfm)); + + rctx->cmd = HASH_CMD_ACC_MODE; ++ rctx->op = SHA_OP_INIT; + rctx->flags = 0; + + switch (crypto_ahash_digestsize(tfm)) { +@@ -740,7 +686,7 @@ + rctx->flags |= SHA_FLAGS_HMAC; + } + +- return 0; ++ return aspeed_hace_hash_handle_queue(hace_dev, req); + } + + static int aspeed_sham_digest(struct ahash_request *req) +@@ -1196,7 +1142,7 @@ + for (i = 0; i < ARRAY_SIZE(aspeed_ahash_algs); i++) + crypto_engine_unregister_ahash(&aspeed_ahash_algs[i].alg.ahash); + +- if (hace_dev->version != AST2600_VERSION) ++ if (hace_dev->version == AST2500_VERSION) + return; + + for (i = 0; i < ARRAY_SIZE(aspeed_ahash_algs_g6); i++) +@@ -1218,7 +1164,7 @@ + } + } + +- if (hace_dev->version != AST2600_VERSION) ++ if (hace_dev->version == AST2500_VERSION) + return; + + for (i = 0; i < ARRAY_SIZE(aspeed_ahash_algs_g6); i++) { +@@ -1230,3 +1176,82 @@ + } + } + } + -+ /* initiate the Create_State command and wait on done */ -+ DEBUG("Create the DRBG state\n"); ++static void aspeed_hace_hash_done_task(unsigned long data) ++{ ++ struct aspeed_hace_dev *hace_dev = (struct aspeed_hace_dev *)data; ++ struct aspeed_engine_hash *hash_engine = &hace_dev->hash_engine; + -+ 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; ++ hash_engine->resume(hace_dev); ++} + -+ /* 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 ++int aspeed_hace_hash_init(struct aspeed_hace_dev *hace_dev) ++{ ++ struct aspeed_engine_hash *hash_engine; ++ int rc; + -+ 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); ++ hash_engine = &hace_dev->hash_engine; + -+ } else { -+ /* set the prediction resistance */ -+ err = nisttrng_set_pred_resist(state, pred_resist); -+ if (err) -+ goto ERR; ++ /* Initialize crypto hardware engine structure for hash */ ++ hace_dev->crypt_engine_hash = crypto_engine_alloc_init(hace_dev->dev, ++ true); ++ if (!hace_dev->crypt_engine_hash) { ++ rc = -ENOMEM; ++ goto end; + } + -+ 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); ++ rc = crypto_engine_start(hace_dev->crypt_engine_hash); ++ if (rc) ++ goto err_engine_hash_start; + -+/* Uninstantiate the DRBG state and zeroize */ -+int nisttrng_uninstantiate(struct nist_trng_state *state) -+{ -+ int err; -+ int err_tmp; -+ u32 tmp; ++ tasklet_init(&hash_engine->done_task, aspeed_hace_hash_done_task, ++ (unsigned long)hace_dev); + -+ 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; ++ /* Allocate DMA buffer for hash engine input used */ ++ hash_engine->ahash_src_addr = ++ dmam_alloc_coherent(hace_dev->dev, ++ ASPEED_HASH_SRC_DMA_BUF_LEN, ++ &hash_engine->ahash_src_dma_addr, ++ GFP_KERNEL); ++ if (!hash_engine->ahash_src_addr) { ++ dev_err(hace_dev->dev, "Failed to allocate dma buffer\n"); ++ rc = -ENOMEM; ++ goto err_engine_hash_start; ++ } + -+ //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); -+ } ++ hash_engine->buffer_addr = dmam_alloc_coherent(hace_dev->dev, SHA512_BLOCK_SIZE * 2, ++ &hash_engine->buffer_dma_addr, ++ GFP_KERNEL); ++ if (!hash_engine->buffer_addr) { ++ dev_err(hace_dev->dev, "Failed to allocate DMA buffer\n"); ++ rc = -ENOMEM; ++ goto err_engine_hash_start; + } + -+ /* 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; ++ hash_engine->digest_addr = dmam_alloc_coherent(hace_dev->dev, SHA512_DIGEST_SIZE, ++ &hash_engine->digest_dma_addr, ++ GFP_KERNEL); ++ if (!hash_engine->digest_addr) { ++ dev_err(hace_dev->dev, "Failed to allocate DMA digest buffer\n"); ++ rc = -ENOMEM; ++ goto err_engine_hash_start; ++ } + -+ /* zeroize */ -+ err = nisttrng_zeroize(state); -+ if (err) -+ goto ERR; ++ /* Hash engine hardware initial done, prepare queue lock */ ++ mutex_init(&hash_engine->queue_lock); + -+ if (err == CRYPTO_OK && err_tmp == CRYPTO_NOT_INSTANTIATED) -+ err = CRYPTO_NOT_INSTANTIATED; ++ return 0; + -+ 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); ++err_engine_hash_start: ++ crypto_engine_exit(hace_dev->crypt_engine_hash); ++end: ++ return rc; ++} + -+/* 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) ++void aspeed_hace_hash_remove(struct aspeed_hace_dev *hace_dev) +{ -+ 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); ++ struct aspeed_engine_hash *hash_engine = &hace_dev->hash_engine; + -+ 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); ++ crypto_engine_exit(hace_dev->crypt_engine_hash); ++ 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 @@ + #include "aspeed-hace.h" + #include + #include ++#include + #include + #include + #include + #include + #include + #include ++#include ++#include ++#include + #include + #include +-#include + + #ifdef CONFIG_CRYPTO_DEV_ASPEED_DEBUG + #define HACE_DBG(d, fmt, ...) \ +@@ -24,6 +27,45 @@ + dev_dbg((d)->dev, "%s() " fmt, __func__, ##__VA_ARGS__) + #endif + ++static unsigned char *dummy_key1; ++static unsigned char *dummy_key2; + -+ 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; -+ } ++int find_dummy_key(const char *key, int keylen) ++{ ++ int ret = 0; + -+ pdu_io_write32(state->base + NIST_TRNG_EDU_RBC_CTRL, tmp_rbc); ++ if (dummy_key1 && memcmp(key, dummy_key1, keylen) == 0) ++ ret = 1; ++ else if (dummy_key2 && memcmp(key, dummy_key2, keylen) == 0) ++ ret = 2; + -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; ++ return ret; +} + -+/* Reseed */ -+int nisttrng_reseed(struct nist_trng_state *state, int pred_resist, void *addin_str) ++int aspeed_hace_reset(struct aspeed_hace_dev *hace_dev) +{ -+ int rnc_flag = 0; -+ int err; ++ int rc; + -+ DEBUG(">> %s: pred_resist = %u, additional strign existence = %u\n", -+ __func__, pred_resist, (addin_str) ? 1 : 0); ++ HACE_DBG(hace_dev, "\n"); + -+ 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; ++ if (!hace_dev->rst) ++ return -ENODEV; + -+ rnc_flag = 1; -+ } ++ rc = reset_control_assert(hace_dev->rst); ++ if (rc) { ++ dev_err(hace_dev->dev, "Hace reset failed (assert).\n"); ++ return rc; + } + -+ /* 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; ++ rc = reset_control_deassert(hace_dev->rst); ++ if (rc) { ++ dev_err(hace_dev->dev, "Hace reset failed (deassert).\n"); ++ return rc; + } + -+ /* 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; ++ return 0; ++} + -+ /* 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; + /* HACE interrupt service routine */ + static irqreturn_t aspeed_hace_irq(int irq, void *dev) + { +@@ -51,23 +93,9 @@ + dev_warn(hace_dev->dev, "CRYPTO no active requests.\n"); + } + +- return IRQ_HANDLED; +-} +- +-static void aspeed_hace_crypto_done_task(unsigned long data) +-{ +- struct aspeed_hace_dev *hace_dev = (struct aspeed_hace_dev *)data; +- struct aspeed_engine_crypto *crypto_engine = &hace_dev->crypto_engine; +- +- crypto_engine->resume(hace_dev); +-} ++ HACE_DBG(hace_dev, "handled\n"); + +-static void aspeed_hace_hash_done_task(unsigned long data) +-{ +- struct aspeed_hace_dev *hace_dev = (struct aspeed_hace_dev *)data; +- struct aspeed_engine_hash *hash_engine = &hace_dev->hash_engine; +- +- hash_engine->resume(hace_dev); ++ return IRQ_HANDLED; + } + + static void aspeed_hace_register(struct aspeed_hace_dev *hace_dev) +@@ -93,30 +121,35 @@ + static const struct of_device_id aspeed_hace_of_matches[] = { + { .compatible = "aspeed,ast2500-hace", .data = (void *)5, }, + { .compatible = "aspeed,ast2600-hace", .data = (void *)6, }, ++ { .compatible = "aspeed,ast2700-hace", .data = (void *)7, }, + {}, + }; + + static int aspeed_hace_probe(struct platform_device *pdev) + { +- struct aspeed_engine_crypto *crypto_engine; +- struct aspeed_engine_hash *hash_engine; ++ const struct of_device_id *hace_dev_id; + 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), + GFP_KERNEL); + if (!hace_dev) + return -ENOMEM; + +- hace_dev->version = (uintptr_t)device_get_match_data(&pdev->dev); +- if (!hace_dev->version) { ++ hace_dev_id = of_match_device(aspeed_hace_of_matches, &pdev->dev); ++ if (!hace_dev_id) { + dev_err(&pdev->dev, "Failed to match hace dev id\n"); + return -EINVAL; + } + + hace_dev->dev = &pdev->dev; +- hash_engine = &hace_dev->hash_engine; +- crypto_engine = &hace_dev->crypto_engine; ++ hace_dev->version = (unsigned long)hace_dev_id->data; + + platform_set_drvdata(pdev, hace_dev); + +@@ -149,115 +182,93 @@ + return rc; + } + +- /* Initialize crypto hardware engine structure for hash */ +- hace_dev->crypt_engine_hash = crypto_engine_alloc_init(hace_dev->dev, +- true); +- if (!hace_dev->crypt_engine_hash) { +- rc = -ENOMEM; +- goto clk_exit; +- } +- +- rc = crypto_engine_start(hace_dev->crypt_engine_hash); +- if (rc) +- goto err_engine_hash_start; +- +- tasklet_init(&hash_engine->done_task, aspeed_hace_hash_done_task, +- (unsigned long)hace_dev); +- +- /* Initialize crypto hardware engine structure for crypto */ +- hace_dev->crypt_engine_crypto = crypto_engine_alloc_init(hace_dev->dev, +- true); +- if (!hace_dev->crypt_engine_crypto) { +- rc = -ENOMEM; +- goto err_engine_hash_start; +- } +- +- rc = crypto_engine_start(hace_dev->crypt_engine_crypto); +- if (rc) +- goto err_engine_crypto_start; +- +- tasklet_init(&crypto_engine->done_task, aspeed_hace_crypto_done_task, +- (unsigned long)hace_dev); +- +- /* Allocate DMA buffer for hash engine input used */ +- hash_engine->ahash_src_addr = +- dmam_alloc_coherent(&pdev->dev, +- ASPEED_HASH_SRC_DMA_BUF_LEN, +- &hash_engine->ahash_src_dma_addr, +- GFP_KERNEL); +- if (!hash_engine->ahash_src_addr) { +- dev_err(&pdev->dev, "Failed to allocate dma buffer\n"); +- rc = -ENOMEM; +- goto err_engine_crypto_start; +- } +- +- /* Allocate DMA buffer for crypto engine context used */ +- crypto_engine->cipher_ctx = +- dmam_alloc_coherent(&pdev->dev, +- PAGE_SIZE, +- &crypto_engine->cipher_ctx_dma, +- GFP_KERNEL); +- if (!crypto_engine->cipher_ctx) { +- dev_err(&pdev->dev, "Failed to allocate cipher ctx dma\n"); +- rc = -ENOMEM; +- goto err_engine_crypto_start; +- } +- +- /* Allocate DMA buffer for crypto engine input used */ +- crypto_engine->cipher_addr = +- dmam_alloc_coherent(&pdev->dev, +- ASPEED_CRYPTO_SRC_DMA_BUF_LEN, +- &crypto_engine->cipher_dma_addr, +- GFP_KERNEL); +- if (!crypto_engine->cipher_addr) { +- dev_err(&pdev->dev, "Failed to allocate cipher addr dma\n"); +- rc = -ENOMEM; +- goto err_engine_crypto_start; +- } +- +- /* Allocate DMA buffer for crypto engine output used */ +- if (hace_dev->version == AST2600_VERSION) { +- crypto_engine->dst_sg_addr = +- dmam_alloc_coherent(&pdev->dev, +- ASPEED_CRYPTO_DST_DMA_BUF_LEN, +- &crypto_engine->dst_sg_dma_addr, +- GFP_KERNEL); +- if (!crypto_engine->dst_sg_addr) { +- 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); + } + -+ /* 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; ++ rc = reset_control_deassert(hace_dev->rst); ++ if (rc) { ++ dev_err(&pdev->dev, "Deassert hace reset failed\n"); ++ return rc; + } + -+ /* 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; ++ rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); ++ if (rc) { ++ dev_warn(&pdev->dev, "No suitable DMA available\n"); ++ return rc; + } + -+ 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); ++ /* Init mutex lock for supporting hace concurrent*/ ++ sema_init(&hace_dev->lock, 1); + -+ } 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); ++#ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_HASH ++ rc = aspeed_hace_hash_init(hace_dev); ++ if (rc) { ++ dev_err(&pdev->dev, "Hash init failed\n"); ++ return rc; ++ } ++#endif ++#ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_CRYPTO ++ rc = aspeed_hace_crypto_init(hace_dev); ++ if (rc) { ++ dev_err(&pdev->dev, "Crypto init failed\n"); ++ return rc; + } + -+ 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 (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"); ++ } + } + -+ if (vtrng > state->config.edu_build_cfg0.public_vtrng_channels) { -+ DEBUG("vtrng channel invalid (%u)\n", vtrng); -+ err = CRYPTO_FAILED; -+ goto ERR; ++ 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); + + dev_info(&pdev->dev, "Aspeed Crypto Accelerator successfully registered\n"); + + return 0; +- +-err_engine_crypto_start: +- crypto_engine_exit(hace_dev->crypt_engine_crypto); +-err_engine_hash_start: +- crypto_engine_exit(hace_dev->crypt_engine_hash); +-clk_exit: +- clk_disable_unprepare(hace_dev->clk); +- +- return rc; + } + + static void aspeed_hace_remove(struct platform_device *pdev) + { + struct aspeed_hace_dev *hace_dev = platform_get_drvdata(pdev); +- struct aspeed_engine_crypto *crypto_engine = &hace_dev->crypto_engine; +- struct aspeed_engine_hash *hash_engine = &hace_dev->hash_engine; + + aspeed_hace_unregister(hace_dev); + +- crypto_engine_exit(hace_dev->crypt_engine_hash); +- crypto_engine_exit(hace_dev->crypt_engine_crypto); ++#ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_HASH ++ aspeed_hace_hash_remove(hace_dev); ++#endif + +- tasklet_kill(&hash_engine->done_task); +- tasklet_kill(&crypto_engine->done_task); ++#ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_CRYPTO ++ aspeed_hace_crypto_remove(hace_dev); ++#endif + + clk_disable_unprepare(hace_dev->clk); + } +@@ -266,7 +277,7 @@ + + static struct platform_driver aspeed_hace_driver = { + .probe = aspeed_hace_probe, +- .remove_new = aspeed_hace_remove, ++ .remove = aspeed_hace_remove, + .driver = { + .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 +@@ -10,6 +10,8 @@ + #include + #include + #include ++#include ++#include + + /***************************** + * * +@@ -23,7 +25,7 @@ + #define ASPEED_HACE_CMD 0x10 /* Crypto Engine Command Register */ + + /* G5 */ +-#define ASPEED_HACE_TAG 0x18 /* HACE Tag Register */ ++#define ASPEED_HACE_TAG 0x18 /* HACE Tag Write Buffer Base Address Register */ + /* 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 @@ + #define ASPEED_HACE_HASH_DATA_LEN 0x2C /* Hash Data Length Register */ + #define ASPEED_HACE_HASH_CMD 0x30 /* Hash Engine Command Register */ + ++/* G7 */ ++#define ASPEED_HACE_SRC_H 0x80 /* Crypto Data Source Base High Address Register */ ++#define ASPEED_HACE_DEST_H 0x84 /* Crypto Data Destination Base High Address Register */ ++#define ASPEED_HACE_CONTEXT_H 0x88 /* Crypto Context Buffer Base High Address Register */ ++#define ASPEED_HACE_TAG_H 0x8C /* HACE Tag Write Buffer Base High Address Register */ ++#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 */ + -+ if (state->status.edu_vstat.rnc_enabled == 0) { -+ DEBUG("rnc_disabled\n"); -+ } + /* crypto cmd */ + #define HACE_CMD_SINGLE_DES 0 + #define HACE_CMD_TRIPLE_DES BIT(17) +@@ -109,8 +120,9 @@ + + #define CRYPTO_FLAGS_BUSY BIT(1) + +-#define SHA_OP_UPDATE 1 +-#define SHA_OP_FINAL 2 ++#define SHA_OP_INIT BIT(0) ++#define SHA_OP_UPDATE BIT(1) ++#define SHA_OP_FINAL BIT(2) + + #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) + ++#define DUMMY_KEY_SIZE 32 + -+ if (state->status.edu_vstat.seed_enum == 0) { -+ DEBUG("not seed_enum\n"); -+ } + struct aspeed_hace_dev; + struct scatterlist; + +@@ -147,10 +161,21 @@ + unsigned long flags; + struct ahash_request *req; + ++ /* Protects hash engine operation enqueue in order */ ++ struct mutex queue_lock; + -+ /* 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); + /* input buffer */ + void *ahash_src_addr; + dma_addr_t ahash_src_dma_addr; + ++ /* remain data buffer */ ++ u8 *buffer_addr; ++ dma_addr_t buffer_dma_addr; + -+ 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); ++ /* output buffer */ ++ void *digest_addr; ++ dma_addr_t digest_dma_addr; + -+ // check busy -+ err = nisttrng_vtrng_wait_on_busy(state, 0, vtrng); -+ if (err) -+ goto ERR; + dma_addr_t src_dma; + dma_addr_t digest_dma; + +@@ -192,12 +217,10 @@ + + /* remain data buffer */ + u8 buffer[SHA512_BLOCK_SIZE * 2]; +- dma_addr_t buffer_dma_addr; + size_t bufcnt; /* buffer counter */ + + /* output buffer */ +- u8 digest[SHA512_DIGEST_SIZE] __aligned(64); +- dma_addr_t digest_dma_addr; ++ u8 digest[SHA512_DIGEST_SIZE]; + u64 digcnt[2]; + }; + +@@ -220,12 +243,14 @@ + + /* callback func */ + aspeed_hace_fn_t resume; ++ int load_vault_key; + }; + + struct aspeed_cipher_ctx { + struct aspeed_hace_dev *hace_dev; + int key_len; + u8 key[AES_MAX_KEYLENGTH]; ++ int dummy_key; + + /* callback func */ + aspeed_hace_fn_t start; +@@ -243,11 +268,16 @@ + + struct aspeed_hace_dev { + void __iomem *regs; ++ void __iomem *sec_regs; + struct device *dev; + int irq; + struct clk *clk; ++ struct reset_control *rst; + unsigned long version; + ++ /* Protects hace register access */ ++ struct semaphore lock; + -+ // 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); -+ } + struct crypto_engine *crypt_engine_hash; + struct crypto_engine *crypt_engine_crypto; + +@@ -268,7 +298,8 @@ + + enum aspeed_version { + AST2500_VERSION = 5, +- AST2600_VERSION ++ AST2600_VERSION, ++ AST2700_VERSION, + }; + + #define ast_hace_write(hace, val, offset) \ +@@ -280,5 +311,11 @@ + 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_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 +@@ -0,0 +1,901 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright 2023 Aspeed Technology Inc. ++ */ + -+ // 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); -+ } ++#include ++#include ++#include ++#include "aspeed-rsss.h" + -+ /* 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); ++//#define RSSS_SHA3_POLLING_MODE + -+ /* 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); ++static int aspeed_sha3_self_test(struct aspeed_rsss_dev *rsss_dev) ++{ ++ u32 pattern = 0xbeef; ++ u32 val; + -+ /* 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; -+ } -+ } -+ } ++ ast_rsss_write(rsss_dev, pattern, ASPEED_SHA3_SRC_LO); ++ val = ast_rsss_read(rsss_dev, ASPEED_SHA3_SRC_LO); ++ if (val != pattern) ++ return -EIO; + -+ err = CRYPTO_OK; -+ state->status.current_state = NIST_TRNG_STATE_GENERATE; -+ERR: -+ if (err) -+ random_bits = NULL; ++ ast_rsss_write(rsss_dev, 0x0, ASPEED_SHA3_SRC_LO); ++ val = ast_rsss_read(rsss_dev, ASPEED_SHA3_SRC_LO); ++ if (val) ++ return -EIO; + -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; ++ return 0; +} + -+static int nisttrng_generate_private_vtrng(struct nist_trng_state *state, void *random_bits, -+ unsigned long req_num_bytes) ++static int aspeed_sha3_dma_prepare(struct aspeed_rsss_dev *rsss_dev) +{ -+ int err; -+ u32 tmp; -+ unsigned int remained_bytes; -+ unsigned long req_num_blks; -+ int i, j; ++ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; ++ struct ahash_request *req = sha3_engine->req; ++ struct aspeed_sha3_reqctx *rctx; ++ int length, remain; + -+ DEBUG(">> %s : requested number of bytes = %lu ", -+ __func__, req_num_bytes); ++ rctx = ahash_request_ctx(req); ++ remain = (rctx->total + rctx->bufcnt) % rctx->blksize; ++ length = rctx->total + rctx->bufcnt - remain; + -+ /* 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; -+ } ++ RSSS_DBG(rsss_dev, "%s:0x%x, %s:%zu, %s:0x%x, %s:0x%x, %s:0x%x\n", ++ "rctx total", rctx->total, "bufcnt", rctx->bufcnt, ++ "offset", rctx->offset, "length", length, ++ "remain", remain); + -+ /* 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 (rctx->bufcnt) ++ memcpy(sha3_engine->ahash_src_addr, rctx->buffer, ++ rctx->bufcnt); + -+ if (state->status.edu_vstat.rnc_enabled == 0) { -+ DEBUG("rnc_disabled\n"); -+ } ++ if (length < ASPEED_HASH_SRC_DMA_BUF_LEN) { ++ scatterwalk_map_and_copy(sha3_engine->ahash_src_addr + rctx->bufcnt, ++ rctx->src_sg, rctx->offset, ++ rctx->total - remain, 0); ++ rctx->offset += rctx->total - remain; + -+ if (state->status.edu_vstat.seed_enum == 0) { -+ DEBUG("not seed_enum\n"); ++ } else { ++ dev_warn(rsss_dev->dev, "SHA3 input data length is too large\n"); ++ return -EINVAL; + } + -+ /* 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); ++ /* Copy remain data into buffer */ ++ scatterwalk_map_and_copy(rctx->buffer, rctx->src_sg, ++ rctx->offset, remain, 0); ++ rctx->bufcnt = remain; + -+ // check busy -+ err = nisttrng_vtrng_wait_on_busy(state, 1, 0); -+ if (err) -+ goto ERR; ++ sha3_engine->src_length = length; ++ sha3_engine->src_dma = sha3_engine->ahash_src_dma_addr; + -+ // 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); -+ } ++ return 0; ++} + -+ //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); -+ } ++/* ++ * Prepare DMA buffer as SG list buffer before ++ * hardware engine processing. ++ */ ++static int aspeed_sha3_dma_prepare_sg(struct aspeed_rsss_dev *rsss_dev) ++{ ++ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; ++ struct ahash_request *req = sha3_engine->req; ++ struct aspeed_sha3_reqctx *rctx; ++ struct aspeed_sg_list *src_list; ++ struct scatterlist *s; ++ int length, remain, sg_len; ++ int i, rc = 0; + -+ /* 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); ++ rctx = ahash_request_ctx(req); ++ remain = (rctx->total + rctx->bufcnt) % rctx->blksize; ++ length = rctx->total + rctx->bufcnt - remain; + -+ /* 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); ++ RSSS_DBG(rsss_dev, "%s:0x%x, %s:%zu, %s:0x%x, %s:0x%x\n", ++ "rctx total", rctx->total, "bufcnt", rctx->bufcnt, ++ "length", length, "remain", remain); + -+ /* 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; -+ } -+ } ++ sg_len = dma_map_sg(rsss_dev->dev, rctx->src_sg, rctx->src_nents, ++ DMA_TO_DEVICE); ++ /* ++ * Need dma_sync_sg_for_device()? ++ */ ++ if (!sg_len) { ++ dev_warn(rsss_dev->dev, "dma_map_sg() src error\n"); ++ rc = -ENOMEM; ++ goto end; + } -+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; ++ src_list = (struct aspeed_sg_list *)sha3_engine->ahash_src_addr; + -+ 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); ++ if (rctx->bufcnt != 0) { ++ u64 phy_addr; ++ u32 len; + -+ /* make sure there is no alarm and the core is not busy */ -+ err = nisttrng_get_alarms(state); -+ if (err) -+ goto ERR; ++ phy_addr = sha3_engine->buffer_dma_addr; ++ len = rctx->bufcnt; ++ length -= len; + -+ 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; -+ } ++ /* Last sg list */ ++ if (length == 0) ++ len |= SG_LAST_LIST; + -+ /* 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; ++ src_list[0].phy_addr = cpu_to_le64(phy_addr); ++ src_list[0].len = cpu_to_le32(len); + -+ /* 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; ++ RSSS_DBG(rsss_dev, "Remain buffer first, addr:%llx, len:0x%x\n", ++ src_list[0].phy_addr, src_list[0].len); + -+ /* make sure random_bits is not NULL */ -+ if (!random_bits) { -+ DEBUG("random_bits pointer cannot be NULL\n"); -+ err = CRYPTO_FAILED; -+ goto ERR; ++ src_list++; + } + -+ /* 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; -+ } ++ if (length != 0) { ++ for_each_sg(rctx->src_sg, s, sg_len, i) { ++ u64 phy_addr = sg_dma_address(s); ++ u32 len = sg_dma_len(s); ++ u8 *va = sg_virt(s); + -+ do { -+ void *generate_addin_str = addin_str; ++ RSSS_DBG(rsss_dev, "SG[%d] PA:%llx, VA:%llx, len:0x%x\n", ++ i, sg_dma_address(s), (u64)va, len); + -+ if (pred_resist | reseed_required) { -+ err = nisttrng_reseed(state, pred_resist, addin_str); -+ if (err) -+ goto ERR; ++ if (length > len) { ++ length -= len; ++ } else { ++ /* Last sg list */ ++ len = length; ++ len |= SG_LAST_LIST; ++ length = 0; ++ } + -+ /* 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; ++ src_list[i].phy_addr = cpu_to_le64(phy_addr); ++ src_list[i].len = cpu_to_le32(len); + -+ /* ADDIN_PRESENT field in MODE has to be set back to 0 to avoid illegal cmd sequence */ -+ reseed_required = 0; ++ len = len & 0xffff; + } ++ } + -+ /* generate process */ -+ if (nisttrng_check_seed_lifetime(state) == CRYPTO_RESEED_REQUIRED) { -+ reseed_required = 1; ++ if (length != 0) { ++ rc = -EINVAL; ++ goto free_src_sg; ++ } + -+ } else { -+ reseed_required = 0; ++ rctx->offset = rctx->total - remain; ++ sha3_engine->src_length = rctx->total + rctx->bufcnt - remain; ++ sha3_engine->src_dma = sha3_engine->ahash_src_dma_addr; + -+ /* 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; -+ } ++ return 0; + -+ /* Generate all random bits */ -+ /* if EDU present then get random number from private vtrng */ ++free_src_sg: ++ RSSS_DBG(rsss_dev, "dma_unmap_sg()\n"); ++ dma_unmap_sg(rsss_dev->dev, rctx->src_sg, rctx->src_nents, ++ DMA_TO_DEVICE); ++end: ++ return rc; ++} + -+ //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; ++static int aspeed_sha3_complete(struct aspeed_rsss_dev *rsss_dev) ++{ ++ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; ++ struct ahash_request *req = sha3_engine->req; + -+ } else { -+ err = nisttrng_gen_random(state, random_bits, -+ req_num_bytes); -+ if (err) -+ goto ERR; ++ RSSS_DBG(rsss_dev, "\n"); + -+ /* 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); ++ sha3_engine->flags &= ~CRYPTO_FLAGS_BUSY; + -+ err = CRYPTO_OK; -+ state->status.current_state = NIST_TRNG_STATE_GENERATE; -+ERR: -+ if (err) -+ random_bits = NULL; ++ crypto_finalize_hash_request(rsss_dev->crypt_engine_sha3, req, 0); ++ ++ return 0; ++} + -+ 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-04-08 18:03:46.630736014 +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. ++ * Copy digest to the corresponding request result. ++ * This function will be called at final() stage. + */ ++static int aspeed_sha3_transfer(struct aspeed_rsss_dev *rsss_dev) ++{ ++ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; ++ struct ahash_request *req = sha3_engine->req; ++ struct aspeed_sha3_reqctx *rctx; + -+#include "nisttrng_hw.h" -+#include "nisttrng.h" ++ RSSS_DBG(rsss_dev, "\n"); + -+/* Wait functions */ -+static int nisttrng_wait_on_(struct nist_trng_state *state, u32 mask) -+{ -+ u32 tmp; -+ int t; ++ rctx = ahash_request_ctx(req); + -+ t = NIST_TRNG_RETRY_MAX; ++ /* add usleep for DMA done */ ++ udelay(8); ++ memcpy(req->result, sha3_engine->digest_addr, rctx->digsize); + -+ do { -+ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_ISTAT); -+ } while (!(tmp & (mask | NIST_TRNG_REG_ISTAT_ALARMS)) && --t); ++ return aspeed_sha3_complete(rsss_dev); ++} + -+ if (tmp & NIST_TRNG_REG_ISTAT_ALARMS) -+ return nisttrng_get_alarms(state); ++#ifdef RSSS_SHA3_POLLING_MODE ++static int aspeed_sha3_wait_complete(struct aspeed_rsss_dev *rsss_dev) ++{ ++ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; ++ u32 sts; ++ int ret; + -+ if (t) { -+ pdu_io_write32(state->base + NIST_TRNG_REG_ISTAT, mask); -+ return CRYPTO_OK; ++ ret = readl_poll_timeout(rsss_dev->regs + ASPEED_SHA3_BUSY_STS, sts, ++ ((sts & SHA3_STS) == 0x0), ++ ASPEED_RSSS_POLLING_TIME, ++ ASPEED_RSSS_TIMEOUT * 10); ++ if (ret) { ++ dev_err(rsss_dev->dev, "SHA3 wrong engine status\n"); ++ return -EIO; ++ } + -+ } else { -+ SYNHW_PRINT("wait_on_: failed timeout: %08lx\n", -+ (unsigned long)tmp); -+ return CRYPTO_TIMEOUT; ++ ret = readl_poll_timeout(rsss_dev->regs + ASPEED_RSSS_INT_STS, sts, ++ ((sts & SHA3_INT_DONE) == SHA3_INT_DONE), ++ ASPEED_RSSS_POLLING_TIME, ++ ASPEED_RSSS_TIMEOUT); ++ if (ret) { ++ dev_err(rsss_dev->dev, "SHA3 wrong interrupt status\n"); ++ return -EIO; + } -+} /* 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); ++ ast_rsss_write(rsss_dev, sts, ASPEED_RSSS_INT_STS); + -+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 */ ++ RSSS_DBG(rsss_dev, "irq sts:0x%x\n", sts); + -+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 */ ++ if (sts & SHA3_INT_DONE) { ++ if (sha3_engine->flags & CRYPTO_FLAGS_BUSY) ++ tasklet_schedule(&sha3_engine->done_task); ++ else ++ dev_err(rsss_dev->dev, "SHA3 no active requests.\n"); ++ } + -+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 */ ++ return 0; ++} ++#endif + -+int nisttrng_wait_on_busy(struct nist_trng_state *state) ++/* ++ * Trigger hardware engines to do the math. ++ */ ++static int aspeed_sha3_trigger(struct aspeed_rsss_dev *rsss_dev, ++ aspeed_rsss_fn_t resume) +{ -+ u32 tmp, t; -+ -+ t = NIST_TRNG_RETRY_MAX; ++ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; ++ struct ahash_request *req = sha3_engine->req; ++ struct aspeed_sha3_reqctx *rctx; + -+ do { -+ tmp = pdu_io_read32(state->base + NIST_TRNG_REG_STAT); -+ } while ((tmp & NIST_TRNG_REG_STAT_BUSY) && --t); ++ RSSS_DBG(rsss_dev, "src_dma:%pad, digest_dma:%pad, length:%zu\n", ++ &sha3_engine->src_dma, &sha3_engine->digest_dma_addr, ++ sha3_engine->src_length); + -+ if (t) -+ return CRYPTO_OK; ++ rctx = ahash_request_ctx(req); ++ sha3_engine->resume = resume; + -+ 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); ++ memcpy(sha3_engine->digest_addr, rctx->digest, rctx->digsize); ++ memcpy(sha3_engine->buffer_addr, rctx->buffer, rctx->bufcnt); + -+/* Read and return alarm. Zeroize if there is an alarm*/ -+int nisttrng_get_alarms(struct nist_trng_state *state) -+{ -+ u32 tmp; ++ ast_rsss_write(rsss_dev, sha3_engine->src_dma, ++ ASPEED_SHA3_SRC_LO); ++ /* TODO - SRC_HI */ ++ ast_rsss_write(rsss_dev, sha3_engine->src_dma >> 32, ++ ASPEED_SHA3_SRC_HI); + -+ 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; ++ ast_rsss_write(rsss_dev, sha3_engine->digest_dma_addr, ++ ASPEED_SHA3_DST_LO); ++ /* TODO - DST_HI */ ++ ast_rsss_write(rsss_dev, sha3_engine->digest_dma_addr >> 32, ++ ASPEED_SHA3_DST_HI); + -+ /* 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 (!sha3_engine->sg_mode) ++ ast_rsss_write(rsss_dev, sha3_engine->src_length, ++ ASPEED_SHA3_SRC_LEN); + -+ if (state->status.alarm_code) -+ return CRYPTO_FATAL; -+ else -+ return CRYPTO_OK; -+} /* nisttrng_get_alarms */ -+EXPORT_SYMBOL(nisttrng_get_alarms); ++ ast_rsss_write(rsss_dev, rctx->cmd, ASPEED_SHA3_CMD); + -+/* 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; ++ /* Memory barrier to ensure all data setup before engine starts */ ++ mb(); + -+ return 0; -+} /* nisttrng_reset_counters */ -+EXPORT_SYMBOL(nisttrng_reset_counters); ++ rctx->cmd |= SHA3_CMD_TRIG; + -+/* 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; ++ RSSS_DBG(rsss_dev, "cmd:0x%x\n", rctx->cmd); + -+ return 0; -+} /* nisttrng_reset_state */ ++ ast_rsss_write(rsss_dev, rctx->cmd, ASPEED_SHA3_CMD); + -+/* ---------- Set field APIs ---------- */ ++#ifdef RSSS_SHA3_POLLING_MODE ++ return aspeed_sha3_wait_complete(rsss_dev); ++#else ++ return -EINPROGRESS; ++#endif ++} + -+/* -+ * 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) ++static int aspeed_sha3_req_final(struct aspeed_rsss_dev *rsss_dev) +{ -+ int err; -+ u32 tmp; -+ enum nisttrng_sec_strength chosen_sec_strength; ++ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; ++ struct ahash_request *req = sha3_engine->req; ++ struct aspeed_sha3_reqctx *rctx = ahash_request_ctx(req); ++ int remain_pad; ++ u8 *src; + -+ DEBUG(">> %s: security strength = %i\n", __func__, -+ req_sec_strength); ++ RSSS_DBG(rsss_dev, "\n"); + -+ /* 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; ++ /* A0 padding issue */ ++ remain_pad = rctx->blksize - rctx->bufcnt; ++ if (remain_pad < 16) { ++ /* SW padding */ ++ RSSS_DBG(rsss_dev, "Use SW padding, pad size:0x%x\n", ++ remain_pad); ++ src = (u8 *)rctx->buffer; ++ src[rctx->bufcnt] = 0x06; ++ memset(src + rctx->bufcnt + 1, 0, remain_pad - 1); ++ src[rctx->bufcnt + remain_pad - 1] |= 0x80; + -+ } else if (((req_sec_strength > 128) && -+ (req_sec_strength <= 256)) && -+ (state->config.features.drbg_arch == AES256)) { -+ chosen_sec_strength = SEC_STRNT_AES256; ++ rctx->bufcnt += remain_pad; + -+ } 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; ++ rctx->cmd |= SHA3_CMD_HW_PAD; + } -+ 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; ++ if (sha3_engine->sg_mode) { ++ struct aspeed_sg_list *src_list = ++ (struct aspeed_sg_list *)sha3_engine->ahash_src_addr; ++ u64 phy_addr; ++ u32 len; + -+ } 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); ++ phy_addr = sha3_engine->buffer_dma_addr; ++ len = rctx->bufcnt; ++ len |= SG_LAST_LIST; + -+ state->status.pad_ps_addin = 0; -+ state->status.sec_strength = chosen_sec_strength; -+ } ++ src_list[0].phy_addr = cpu_to_le64(phy_addr); ++ src_list[0].len = cpu_to_le32(len); + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_set_sec_strength */ -+EXPORT_SYMBOL(nisttrng_set_sec_strength); ++ RSSS_DBG(rsss_dev, "Final SG, addr:%llx, len:0x%x\n", ++ src_list[0].phy_addr, src_list[0].len); + -+/* -+ * 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; ++ rctx->cmd |= SHA3_CMD_SG_MODE; ++ sha3_engine->src_dma = sha3_engine->ahash_src_dma_addr; + -+ DEBUG(">> %s, adding_present = %u\n", __func__, -+ addin_present); ++ } else { ++ sha3_engine->src_dma = sha3_engine->buffer_dma_addr; ++ sha3_engine->src_length = rctx->bufcnt; ++ } + -+ 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); ++ rctx->cmd |= SHA3_CMD_ACC_FINAL; + -+ DEBUG("--- Return %s, err = %i\n", __func__, 0); -+ return 0; -+} /* nisttrng_set_addin_present */ -+EXPORT_SYMBOL(nisttrng_set_addin_present); ++ return aspeed_sha3_trigger(rsss_dev, aspeed_sha3_transfer); ++} + -+/* -+ * 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) ++static int aspeed_sha3_update_resume(struct aspeed_rsss_dev *rsss_dev) +{ -+ int err; -+ u32 tmp; ++ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; ++ struct ahash_request *req = sha3_engine->req; ++ struct aspeed_sha3_reqctx *rctx; + -+ DEBUG(">> %s: pred_resist = %u\n", __func__, pred_resist); ++ RSSS_DBG(rsss_dev, "\n"); + -+ /* 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; -+ } ++ rctx = ahash_request_ctx(req); + -+ 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); ++ memcpy(rctx->digest, sha3_engine->digest_addr, rctx->digsize); ++ rctx->cmd &= ~SHA3_CMD_TRIG; + -+ state->status.pred_resist = pred_resist; ++ if (rctx->flags & SHA3_FLAGS_FINUP) ++ return aspeed_sha3_req_final(rsss_dev); + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_set_pred_resist */ -+EXPORT_SYMBOL(nisttrng_set_pred_resist); ++ return aspeed_sha3_complete(rsss_dev); ++} + -+/* -+ * 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) ++static int aspeed_sha3_update_resume_sg(struct aspeed_rsss_dev *rsss_dev) +{ -+ int err; -+ u32 tmp; -+ int t; -+ -+ DEBUG(">> %s: secure_mode = %u\n", __func__, secure_mode); ++ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; ++ struct ahash_request *req = sha3_engine->req; ++ struct aspeed_sha3_reqctx *rctx; ++ int remain; + -+ t = NIST_TRNG_RETRY_MAX; ++ RSSS_DBG(rsss_dev, "\n"); + -+ 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); ++ rctx = ahash_request_ctx(req); + -+ /* 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); ++ memcpy(rctx->digest, sha3_engine->digest_addr, rctx->digsize); ++ remain = rctx->total - rctx->offset; + -+ if (!t) { -+ err = CRYPTO_TIMEOUT; -+ goto ERR; -+ } ++ RSSS_DBG(rsss_dev, "Copy remain data from 0x%x, size:0x%x\n", ++ rctx->offset, remain); + -+ /* 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); -+ } ++ dma_unmap_sg(rsss_dev->dev, rctx->src_sg, rctx->src_nents, ++ DMA_TO_DEVICE); + -+ state->status.secure_mode = secure_mode; ++ scatterwalk_map_and_copy(rctx->buffer, rctx->src_sg, rctx->offset, ++ remain, 0); + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_set_secure_mode */ -+EXPORT_SYMBOL(nisttrng_set_secure_mode); ++ rctx->bufcnt = remain; ++ rctx->cmd &= ~(SHA3_CMD_TRIG | SHA3_CMD_SG_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; ++ if (rctx->flags & SHA3_FLAGS_FINUP) ++ return aspeed_sha3_req_final(rsss_dev); + -+ DEBUG(">> %s: nonce_mode = %u\n", __func__, nonce_mode); ++ return aspeed_sha3_complete(rsss_dev); ++} + -+ t = NIST_TRNG_RETRY_MAX; ++static int aspeed_sha3_req_update(struct aspeed_rsss_dev *rsss_dev) ++{ ++ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; ++ struct ahash_request *req = sha3_engine->req; ++ struct aspeed_sha3_reqctx *rctx; ++ aspeed_rsss_fn_t resume; ++ int ret; + -+ 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); ++ RSSS_DBG(rsss_dev, "\n"); + -+ /* 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); ++ rctx = ahash_request_ctx(req); + -+ if (!t) { -+ err = CRYPTO_TIMEOUT; -+ goto ERR; -+ } ++ if (sha3_engine->sg_mode) { ++ rctx->cmd |= SHA3_CMD_SG_MODE; ++ resume = aspeed_sha3_update_resume_sg; + -+ /* 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); ++ } else { ++ resume = aspeed_sha3_update_resume; + } + -+ state->status.nonce_mode = nonce_mode; ++ ret = sha3_engine->dma_prepare(rsss_dev); ++ if (ret) ++ return ret; + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_set_nonce_mode */ -+EXPORT_SYMBOL(nisttrng_set_nonce_mode); ++ return aspeed_sha3_trigger(rsss_dev, resume); ++} + -+/* ---------- 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) ++static int aspeed_sha3_do_request(struct crypto_engine *engine, void *areq) +{ -+ int err; -+ int i, j; -+ int str_size; ++ struct ahash_request *req = ahash_request_cast(areq); ++ struct aspeed_sha3_reqctx *rctx = ahash_request_ctx(req); ++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); ++ struct aspeed_sha3_ctx *tctx = crypto_ahash_ctx(tfm); ++ struct aspeed_rsss_dev *rsss_dev = tctx->rsss_dev; ++ struct aspeed_engine_sha3 *sha3_engine; ++ int ret = 0; + -+ DEBUG(">> %s starts...\n", __func__); ++ RSSS_DBG(rsss_dev, "\n"); + -+ /* return error if the pointer is NULL */ -+ if (!input_str) { -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } ++ sha3_engine = &rsss_dev->sha3_engine; ++ sha3_engine->flags |= CRYPTO_FLAGS_BUSY; ++ sha3_engine->req = req; + -+ /* 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 */ ++ if (sha3_engine->sg_mode) ++ sha3_engine->dma_prepare = aspeed_sha3_dma_prepare_sg; ++ else ++ sha3_engine->dma_prepare = aspeed_sha3_dma_prepare; + -+ for (i = 0; i < str_size; i++) { -+ pdu_io_write32(state->base + NIST_TRNG_REG_NPA_DATA0 + i, -+ ((u32 *)input_str)[i]); -+ } ++ if (rctx->op == SHA_OP_UPDATE) ++ ret = aspeed_sha3_req_update(rsss_dev); ++ else if (rctx->op == SHA_OP_FINAL) ++ ret = aspeed_sha3_req_final(rsss_dev); + -+ 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 (ret != -EINPROGRESS) ++ return ret; + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_load_ps_addin */ -+EXPORT_SYMBOL(nisttrng_load_ps_addin); ++ return 0; ++} + -+/* ---------- 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) ++static int aspeed_sha3_handle_queue(struct aspeed_rsss_dev *rsss_dev, ++ struct ahash_request *req) +{ -+ int err; -+ int nonce_ld_cntr = 0; -+ int i, j; ++ struct aspeed_sha3_reqctx *rctx = ahash_request_ctx(req); ++ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; ++ int ret = 0; + -+ DEBUG(">> %s: seeding mode = %s, nonce_operation = %u\n", __func__, -+ (state->status.nonce_mode ? "Nonce" : "Noise"), nonce_operation); ++ if (rctx->op & SHA_OP_INIT) { ++ mutex_lock(&sha3_engine->queue_lock); ++ return 0; ++ } + -+ /* make sure there is no alarm and the core is not busy */ -+ err = nisttrng_get_alarms(state); -+ if (err) -+ goto ERR; ++ ret = crypto_transfer_hash_request_to_engine(rsss_dev->crypt_engine_sha3, ++ req); + -+ err = nisttrng_wait_on_busy(state); -+ if (err) -+ goto ERR; ++ /* The last request is enqueued, release the lock */ ++ if (rctx->op & SHA_OP_FINAL || rctx->flags & SHA3_FLAGS_FINUP) ++ mutex_unlock(&sha3_engine->queue_lock); + -+ /* --- Seeding --- */ -+ if (state->status.nonce_mode) { /* --- nonce mode --- */ -+ if (!input_nonce) { -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } ++ return ret; ++} + -+ nonce_ld_cntr = 0; ++static int aspeed_sha3_update(struct ahash_request *req) ++{ ++ struct aspeed_sha3_reqctx *rctx = ahash_request_ctx(req); ++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); ++ struct aspeed_sha3_ctx *tctx = crypto_ahash_ctx(tfm); ++ struct aspeed_rsss_dev *rsss_dev = tctx->rsss_dev; ++ struct aspeed_engine_sha3 *sha3_engine; + -+ 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; ++ RSSS_DBG(rsss_dev, "req->nbytes: %d\n", req->nbytes); + -+ 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]); -+ } ++ sha3_engine = &rsss_dev->sha3_engine; + -+ /* issue the command and wait on done */ -+ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, -+ NIST_TRNG_REG_CTRL_CMD_GEN_NONCE); ++ rctx->total = req->nbytes; ++ rctx->src_sg = req->src; ++ rctx->offset = 0; ++ rctx->src_nents = sg_nents(req->src); ++ rctx->op = SHA_OP_UPDATE; + -+ if (nisttrng_wait_on_done(state)) { -+ err = CRYPTO_FATAL; -+ goto ERR; -+ }; -+ } ++ RSSS_DBG(rsss_dev, "total:0x%x, src_nents:0x%x\n", rctx->total, rctx->src_nents); + -+ } 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); ++ rctx->digcnt[0] += rctx->total; ++ if (rctx->digcnt[0] < rctx->total) ++ rctx->digcnt[1]++; + -+ if (nisttrng_wait_on_done(state)) { -+ err = CRYPTO_FATAL; -+ goto ERR; -+ }; ++ if (rctx->bufcnt + rctx->total < rctx->blksize) { ++ scatterwalk_map_and_copy(rctx->buffer + rctx->bufcnt, ++ rctx->src_sg, rctx->offset, ++ rctx->total, 0); ++ rctx->bufcnt += rctx->total; ++ ++ return 0; + } + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_get_entropy_input */ -+EXPORT_SYMBOL(nisttrng_get_entropy_input); ++ return aspeed_sha3_handle_queue(rsss_dev, req); ++} + -+/* -+ * 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) ++static int aspeed_sha3_final(struct ahash_request *req) +{ -+ 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; -+ } ++ struct aspeed_sha3_reqctx *rctx = ahash_request_ctx(req); ++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); ++ struct aspeed_sha3_ctx *tctx = crypto_ahash_ctx(tfm); ++ struct aspeed_rsss_dev *rsss_dev = tctx->rsss_dev; + -+ /* make sure there is no alarm and the core is not busy */ -+ err = nisttrng_get_alarms(state); -+ if (err) -+ goto ERR; ++ RSSS_DBG(rsss_dev, "req->nbytes:%d, rctx->total:%d\n", ++ req->nbytes, rctx->total); ++ rctx->op = SHA_OP_FINAL; + -+ err = nisttrng_wait_on_busy(state); -+ if (err) -+ goto ERR; ++ return aspeed_sha3_handle_queue(rsss_dev, req); ++} + -+ /* This API should not be called with a NULL additional input string */ -+ if (!addin_str) { -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } ++static int aspeed_sha3_finup(struct ahash_request *req) ++{ ++ struct aspeed_sha3_reqctx *rctx = ahash_request_ctx(req); ++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); ++ struct aspeed_sha3_ctx *tctx = crypto_ahash_ctx(tfm); ++ struct aspeed_rsss_dev *rsss_dev = tctx->rsss_dev; ++ int rc1, rc2; + -+ /* set the ADDIN_PRESENT field of the MODE register to 1 */ -+ err = nisttrng_set_addin_present(state, 1); -+ if (err) -+ goto ERR; ++ RSSS_DBG(rsss_dev, "req->nbytes: %d\n", req->nbytes); + -+ err = nisttrng_load_ps_addin(state, addin_str); -+ if (err) -+ goto ERR; ++ rctx->flags |= SHA3_FLAGS_FINUP; + -+ /* execute the command and wait on done*/ -+ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, -+ NIST_TRNG_REG_CTRL_CMD_REFRESH_ADDIN); ++ rc1 = aspeed_sha3_update(req); ++ if (rc1 == -EINPROGRESS || rc1 == -EBUSY) ++ return rc1; + -+ err = nisttrng_wait_on_done(state); -+ if (err) -+ goto ERR; ++ /* ++ * final() has to be always called to cleanup resources ++ * even if update() failed, except EINPROGRESS ++ */ ++ rc2 = aspeed_sha3_final(req); + -+ err = 0; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_refresh_addin */ -+EXPORT_SYMBOL(nisttrng_refresh_addin); ++ return rc1 ? : rc2; ++} + -+/* -+ * 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) ++static int aspeed_sha3_init(struct ahash_request *req) +{ -+ int err; -+ int i, j; -+ u32 tmp; -+ unsigned int remained_bytes; -+ unsigned long req_num_blks; ++ struct aspeed_sha3_reqctx *rctx = ahash_request_ctx(req); ++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); ++ struct aspeed_sha3_ctx *tctx = crypto_ahash_ctx(tfm); ++ struct aspeed_rsss_dev *rsss_dev = tctx->rsss_dev; + -+ DEBUG(">> %s: req_num_bytes = %lu\n", __func__, req_num_bytes); ++ RSSS_DBG(rsss_dev, "%s: digest size:%d\n", ++ crypto_tfm_alg_name(&tfm->base), ++ crypto_ahash_digestsize(tfm)); + -+ /* if the DRBG is not intantiated return error */ -+ if (!DRBG_INSTANTIATED(state->status.current_state)) { -+ err = CRYPTO_FAILED; -+ goto ERR; ++ rctx->cmd = SHA3_CMD_ACC; ++ rctx->op = SHA_OP_INIT; ++ rctx->flags = 0; ++ ++ switch (crypto_ahash_digestsize(tfm)) { ++ case SHA3_224_DIGEST_SIZE: ++ rctx->cmd |= SHA3_CMD_MODE_224; ++ rctx->flags |= SHA3_FLAGS_SHA224; ++ rctx->digsize = SHA3_224_DIGEST_SIZE; ++ rctx->blksize = SHA3_224_BLOCK_SIZE; ++ break; ++ case SHA3_256_DIGEST_SIZE: ++ rctx->cmd |= SHA3_CMD_MODE_256; ++ rctx->flags |= SHA3_FLAGS_SHA256; ++ rctx->digsize = SHA3_256_DIGEST_SIZE; ++ rctx->blksize = SHA3_256_BLOCK_SIZE; ++ break; ++ case SHA3_384_DIGEST_SIZE: ++ rctx->cmd |= SHA3_CMD_MODE_384; ++ rctx->flags |= SHA3_FLAGS_SHA384; ++ rctx->digsize = SHA3_384_DIGEST_SIZE; ++ rctx->blksize = SHA3_384_BLOCK_SIZE; ++ break; ++ case SHA3_512_DIGEST_SIZE: ++ rctx->cmd |= SHA3_CMD_MODE_512; ++ rctx->flags |= SHA3_FLAGS_SHA512; ++ rctx->digsize = SHA3_512_DIGEST_SIZE; ++ rctx->blksize = SHA3_512_BLOCK_SIZE; ++ break; ++ default: ++ dev_warn(tctx->rsss_dev->dev, "digest size %d not support\n", ++ crypto_ahash_digestsize(tfm)); ++ return -EINVAL; + } + -+ /* make sure there is no alarm and the core is not busy */ -+ err = nisttrng_get_alarms(state); -+ if (err) -+ goto ERR; ++ rctx->bufcnt = 0; ++ rctx->total = 0; ++ rctx->digcnt[0] = 0; ++ rctx->digcnt[1] = 0; + -+ err = nisttrng_wait_on_busy(state); -+ if (err) -+ goto ERR; ++ memset(rctx->digest, 0x0, SHA3_512_DIGEST_SIZE); + -+ /* 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; -+ } ++ return aspeed_sha3_handle_queue(rsss_dev, req); ++} + -+ /* make sure random_bits is not NULL */ -+ if (!random_bits) { -+ DEBUG("random_bits pointer cannot be NULL\n"); -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } ++static int aspeed_sha3_digest(struct ahash_request *req) ++{ ++ return aspeed_sha3_init(req) ? : aspeed_sha3_finup(req); ++} + -+ /* 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); ++static int aspeed_sha3_export(struct ahash_request *req, void *out) ++{ ++ struct aspeed_sha3_reqctx *rctx = ahash_request_ctx(req); + -+ 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); ++ memcpy(out, rctx, sizeof(*rctx)); + -+ err = nisttrng_wait_on_done(state); -+ if (err) -+ goto ERR; ++ return 0; ++} + -+ /* 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); ++static int aspeed_sha3_import(struct ahash_request *req, const void *in) ++{ ++ struct aspeed_sha3_reqctx *rctx = ahash_request_ctx(req); + -+ /* 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; ++ memcpy(rctx, in, sizeof(*rctx)); + -+ if (state->counters.bits_per_req_left < 0) { -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } ++ return 0; ++} + -+ } else { -+ memcpy(random_bits + i * (NIST_TRNG_RAND_BLK_SIZE_BITS / 8) + -+ j * 4, &tmp, remained_bytes); ++static int aspeed_sha3_cra_init(struct crypto_tfm *tfm) ++{ ++ struct ahash_alg *alg = __crypto_ahash_alg(tfm->__crt_alg); ++ struct aspeed_sha3_ctx *tctx = crypto_tfm_ctx(tfm); ++ struct aspeed_rsss_alg *ast_alg; + -+ /* 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; ++ ast_alg = container_of(alg, struct aspeed_rsss_alg, alg.ahash.base); ++ tctx->rsss_dev = ast_alg->rsss_dev; + -+ if (state->counters.bits_per_req_left < 0) { -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } -+ break; -+ } -+ } -+ } ++ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), ++ sizeof(struct aspeed_sha3_reqctx)); + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_gen_random */ -+EXPORT_SYMBOL(nisttrng_gen_random); ++ return 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 -+ */ -+int nisttrng_advance_state(struct nist_trng_state *state) ++static void aspeed_sha3_cra_exit(struct crypto_tfm *tfm) +{ -+ int err; -+ -+ DEBUG(">> %s starts...\n", __func__); ++ struct aspeed_sha3_ctx *tctx = crypto_tfm_ctx(tfm); ++ struct aspeed_rsss_dev *rsss_dev = tctx->rsss_dev; + -+ /* if the DRBG is not intantiated return error */ -+ if (!DRBG_INSTANTIATED(state->status.current_state)) { -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } ++ RSSS_DBG(rsss_dev, "%s\n", crypto_tfm_alg_name(tfm)); ++} + -+ /* make sure there is no alarm and the core is not busy */ -+ err = nisttrng_get_alarms(state); -+ if (err) -+ goto ERR; ++struct aspeed_rsss_alg aspeed_rsss_algs_sha3_224 = { ++ .type = ASPEED_ALGO_TYPE_AHASH, ++ .alg.ahash.base = { ++ .init = aspeed_sha3_init, ++ .update = aspeed_sha3_update, ++ .final = aspeed_sha3_final, ++ .finup = aspeed_sha3_finup, ++ .digest = aspeed_sha3_digest, ++ .export = aspeed_sha3_export, ++ .import = aspeed_sha3_import, ++ .halg = { ++ .digestsize = SHA3_224_DIGEST_SIZE, ++ .statesize = sizeof(struct aspeed_sha3_reqctx), ++ .base = { ++ .cra_name = "sha3-224", ++ .cra_driver_name = "aspeed-sha3-224", ++ .cra_priority = 300, ++ .cra_flags = CRYPTO_ALG_TYPE_AHASH | ++ CRYPTO_ALG_ASYNC | ++ CRYPTO_ALG_KERN_DRIVER_ONLY, ++ .cra_blocksize = SHA3_224_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct aspeed_sha3_ctx), ++ .cra_module = THIS_MODULE, ++ .cra_init = aspeed_sha3_cra_init, ++ .cra_exit = aspeed_sha3_cra_exit, ++ } ++ } ++ }, ++ .alg.ahash.op = { ++ .do_one_request = aspeed_sha3_do_request, ++ }, ++}; + -+ err = nisttrng_wait_on_busy(state); -+ if (err) -+ goto ERR; ++struct aspeed_rsss_alg aspeed_rsss_algs_sha3_256 = { ++ .type = ASPEED_ALGO_TYPE_AHASH, ++ .alg.ahash.base = { ++ .init = aspeed_sha3_init, ++ .update = aspeed_sha3_update, ++ .final = aspeed_sha3_final, ++ .finup = aspeed_sha3_finup, ++ .digest = aspeed_sha3_digest, ++ .export = aspeed_sha3_export, ++ .import = aspeed_sha3_import, ++ .halg = { ++ .digestsize = SHA3_256_DIGEST_SIZE, ++ .statesize = sizeof(struct aspeed_sha3_reqctx), ++ .base = { ++ .cra_name = "sha3-256", ++ .cra_driver_name = "aspeed-sha3-256", ++ .cra_priority = 300, ++ .cra_flags = CRYPTO_ALG_TYPE_AHASH | ++ CRYPTO_ALG_ASYNC | ++ CRYPTO_ALG_KERN_DRIVER_ONLY, ++ .cra_blocksize = SHA3_256_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct aspeed_sha3_ctx), ++ .cra_module = THIS_MODULE, ++ .cra_init = aspeed_sha3_cra_init, ++ .cra_exit = aspeed_sha3_cra_exit, ++ } ++ } ++ }, ++ .alg.ahash.op = { ++ .do_one_request = aspeed_sha3_do_request, ++ }, ++}; + -+ /* 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; ++struct aspeed_rsss_alg aspeed_rsss_algs_sha3_384 = { ++ .type = ASPEED_ALGO_TYPE_AHASH, ++ .alg.ahash.base = { ++ .init = aspeed_sha3_init, ++ .update = aspeed_sha3_update, ++ .final = aspeed_sha3_final, ++ .finup = aspeed_sha3_finup, ++ .digest = aspeed_sha3_digest, ++ .export = aspeed_sha3_export, ++ .import = aspeed_sha3_import, ++ .halg = { ++ .digestsize = SHA3_384_DIGEST_SIZE, ++ .statesize = sizeof(struct aspeed_sha3_reqctx), ++ .base = { ++ .cra_name = "sha3-384", ++ .cra_driver_name = "aspeed-sha3-384", ++ .cra_priority = 300, ++ .cra_flags = CRYPTO_ALG_TYPE_AHASH | ++ CRYPTO_ALG_ASYNC | ++ CRYPTO_ALG_KERN_DRIVER_ONLY, ++ .cra_blocksize = SHA3_384_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct aspeed_sha3_ctx), ++ .cra_module = THIS_MODULE, ++ .cra_init = aspeed_sha3_cra_init, ++ .cra_exit = aspeed_sha3_cra_exit, ++ } ++ } ++ }, ++ .alg.ahash.op = { ++ .do_one_request = aspeed_sha3_do_request, ++ }, ++}; + -+ /* generate is finished, reset the bits_per_req_left counter */ -+ state->counters.bits_per_req_left = state->counters.max_bits_per_req; ++struct aspeed_rsss_alg aspeed_rsss_algs_sha3_512 = { ++ .type = ASPEED_ALGO_TYPE_AHASH, ++ .alg.ahash.base = { ++ .init = aspeed_sha3_init, ++ .update = aspeed_sha3_update, ++ .final = aspeed_sha3_final, ++ .finup = aspeed_sha3_finup, ++ .digest = aspeed_sha3_digest, ++ .export = aspeed_sha3_export, ++ .import = aspeed_sha3_import, ++ .halg = { ++ .digestsize = SHA3_512_DIGEST_SIZE, ++ .statesize = sizeof(struct aspeed_sha3_reqctx), ++ .base = { ++ .cra_name = "sha3-512", ++ .cra_driver_name = "aspeed-sha3-512", ++ .cra_priority = 300, ++ .cra_flags = CRYPTO_ALG_TYPE_AHASH | ++ CRYPTO_ALG_ASYNC | ++ CRYPTO_ALG_KERN_DRIVER_ONLY, ++ .cra_blocksize = SHA3_512_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct aspeed_sha3_ctx), ++ .cra_module = THIS_MODULE, ++ .cra_init = aspeed_sha3_cra_init, ++ .cra_exit = aspeed_sha3_cra_exit, ++ } ++ } ++ }, ++ .alg.ahash.op = { ++ .do_one_request = aspeed_sha3_do_request, ++ }, ++}; + -+ --state->counters.req_per_seed_left; -+ if (state->counters.req_per_seed_left < 0) { -+ err = CRYPTO_FAILED; -+ goto ERR; -+ } /* just a check */ ++static void aspeed_rsss_sha3_done_task(unsigned long data) ++{ ++ struct aspeed_rsss_dev *rsss_dev = (struct aspeed_rsss_dev *)data; ++ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_advance_state */ ++ (void)sha3_engine->resume(rsss_dev); ++} + -+int nisttrng_check_seed_lifetime(struct nist_trng_state *state) ++void aspeed_rsss_sha3_exit(struct aspeed_rsss_dev *rsss_dev) +{ -+ 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; -+ } ++ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; + -+ err = CRYPTO_OK; -+ERR: -+ return err; ++ crypto_engine_exit(rsss_dev->crypt_engine_sha3); ++ tasklet_kill(&sha3_engine->done_task); +} -+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 aspeed_rsss_sha3_init(struct aspeed_rsss_dev *rsss_dev) +{ -+ int err; -+ u32 tmp; ++ struct aspeed_engine_sha3 *sha3_engine; ++ u32 val; ++ int rc; + -+ DEBUG(">> %s: kat_sel = %u, kat_vec = %u\n", __func__, -+ kat_sel, kat_vec); ++ rc = reset_control_deassert(rsss_dev->reset_sha3); ++ if (rc) { ++ dev_err(rsss_dev->dev, "Deassert SHA3 reset failed\n"); ++ goto end; ++ } + -+ /* 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); ++ sha3_engine = &rsss_dev->sha3_engine; + -+ /* issue the command and wait on kat_completed */ -+ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, -+ NIST_TRNG_REG_CTRL_CMD_KAT); ++ /* Initialize crypto hardware engine structure for SHA3 */ ++ rsss_dev->crypt_engine_sha3 = crypto_engine_alloc_init(rsss_dev->dev, true); ++ if (!rsss_dev->crypt_engine_sha3) { ++ rc = -ENOMEM; ++ goto end; ++ } + -+ err = nisttrng_wait_on_kat_completed(state); -+ if (err) -+ goto ERR; ++ rc = crypto_engine_start(rsss_dev->crypt_engine_sha3); ++ if (rc) ++ goto err_engine_sha3_start; + -+ /* check for alarms */ -+ err = nisttrng_get_alarms(state); -+ if (err) -+ goto ERR; ++ tasklet_init(&sha3_engine->done_task, aspeed_rsss_sha3_done_task, ++ (unsigned long)rsss_dev); + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_kat */ -+EXPORT_SYMBOL(nisttrng_kat); ++ /* Allocate DMA buffer for hash engine input used */ ++ sha3_engine->ahash_src_addr = ++ dmam_alloc_coherent(rsss_dev->dev, ++ ASPEED_HASH_SRC_DMA_BUF_LEN, ++ &sha3_engine->ahash_src_dma_addr, ++ GFP_KERNEL); ++ if (!sha3_engine->ahash_src_addr) { ++ dev_err(rsss_dev->dev, "Failed to allocate DMA src buffer\n"); ++ rc = -ENOMEM; ++ goto err_engine_sha3_start; ++ } + -+/* -+ * 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; ++ sha3_engine->buffer_addr = dmam_alloc_coherent(rsss_dev->dev, SHA3_224_BLOCK_SIZE, ++ &sha3_engine->buffer_dma_addr, ++ GFP_KERNEL); ++ if (!sha3_engine->buffer_addr) { ++ dev_err(rsss_dev->dev, "Failed to allocate DMA buffer\n"); ++ rc = -ENOMEM; ++ goto err_engine_sha3_start; ++ } + -+ DEBUG(">> %s starts...\n", __func__); ++ sha3_engine->digest_addr = dmam_alloc_coherent(rsss_dev->dev, SHA3_512_DIGEST_SIZE, ++ &sha3_engine->digest_dma_addr, ++ GFP_KERNEL); ++ if (!sha3_engine->digest_addr) { ++ dev_err(rsss_dev->dev, "Failed to allocate DMA digest buffer\n"); ++ rc = -ENOMEM; ++ goto err_engine_sha3_start; ++ } + -+ /* SEL = 0, Vec = 0 */ -+ err = nisttrng_kat(state, 0, 0); -+ if (err) -+ goto ERR; ++ /* ++ * Set 1 to use scatter-gather mode. ++ * Set 0 to use direct mode. ++ */ ++ sha3_engine->sg_mode = 0; + -+ /* SEL = 0, Vec = 1 */ -+ err = nisttrng_kat(state, 0, 1); -+ if (err) -+ goto ERR; ++ /* Self-test */ ++ rc = aspeed_sha3_self_test(rsss_dev); ++ if (rc) ++ goto err_engine_sha3_start; + -+ /* SEL = 1, Vec = 0 */ -+ err = nisttrng_kat(state, 1, 0); -+ if (err) -+ goto ERR; ++ /* Sha3 engine hardware init done, prepare queue lock */ ++ mutex_init(&sha3_engine->queue_lock); + -+ /* SEL = 1, Vec = 1 */ -+ err = nisttrng_kat(state, 1, 1); -+ if (err) -+ goto ERR; ++ /* Enable SHA3 interrupt */ ++ val = ast_rsss_read(rsss_dev, ASPEED_RSSS_INT_EN); ++ ast_rsss_write(rsss_dev, val | SHA3_INT_EN, ASPEED_RSSS_INT_EN); ++ dev_info(rsss_dev->dev, "Aspeed RSSS SHA3 interrupt mode.\n"); + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} /* nisttrng_full_kat */ -+EXPORT_SYMBOL(nisttrng_full_kat); ++ dev_info(rsss_dev->dev, "Aspeed RSSS SHA3 initialized (%s mode)\n", ++ sha3_engine->sg_mode ? "SG" : "Direct"); + ++ return 0; ++ ++err_engine_sha3_start: ++ crypto_engine_exit(rsss_dev->crypt_engine_sha3); ++end: ++ return rc; ++} +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 @@ ++// SPDX-License-Identifier: GPL-2.0+ +/* -+ * 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. ++ * Copyright 2023 Aspeed Technology Inc. + */ -+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; -+ } ++#include ++#include "aspeed-rsss.h" + -+ /* 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 u8 data_rev[SRAM_BLOCK_SIZE]; ++static u8 data[SRAM_BLOCK_SIZE]; ++static int dbg; + -+ state->counters.max_bits_per_req = max_bits_per_req; -+ state->counters.bits_per_req_left = max_bits_per_req; ++static void hexdump(char *name, unsigned char *buf, unsigned int len) ++{ ++ if (!dbg) ++ return; + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; ++#ifdef CONFIG_CRYPTO_DEV_ASPEED_DEBUG ++ pr_info("%s:\n", name); ++ print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET, ++ 16, 1, buf, len, false); ++#endif +} -+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_rsa_self_test(struct aspeed_rsss_dev *rsss_dev) +{ -+ int err; ++ struct aspeed_engine_rsa *rsa_engine; ++ const u32 pattern = 0xffffffff; ++ u32 val; + -+ DEBUG(">> %s: %llu\n", __func__, max_req_per_seed); ++ rsa_engine = &rsss_dev->rsa_engine; + -+ /* 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 SRAM access control - CPU */ ++ val = ast_rsss_read(rsss_dev, ASPEED_RSSS_CTRL); ++ ast_rsss_write(rsss_dev, val | SRAM_AHB_MODE_CPU, ASPEED_RSSS_CTRL); + -+ /* 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; -+ } ++ writel(pattern, rsa_engine->sram_exp); ++ val = readl(rsa_engine->sram_exp); ++ if (val != pattern) ++ return -EIO; + -+ state->counters.max_req_per_seed = max_req_per_seed; -+ state->counters.req_per_seed_left = max_req_per_seed; ++ writel(0x0, rsa_engine->sram_exp); + -+ err = CRYPTO_OK; -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; ++ return 0; +} -+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 inline struct akcipher_request * ++ akcipher_request_cast(struct crypto_async_request *req) +{ -+ int err; ++ return container_of(req, struct akcipher_request, base); ++} + -+ DEBUG(">> %s: zeroize the core\n", __func__); ++static int aspeed_rsa_do_fallback(struct akcipher_request *req) ++{ ++ struct crypto_akcipher *cipher = crypto_akcipher_reqtfm(req); ++ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(cipher); ++ int err; + -+ /* issue zeroize command */ -+ pdu_io_write32(state->base + NIST_TRNG_REG_CTRL, -+ NIST_TRNG_REG_CTRL_CMD_ZEROIZE); ++ akcipher_request_set_tfm(req, ctx->fallback_tfm); + -+ /* wait on zeroize done */ -+ err = nisttrng_wait_on_zeroize(state); -+ if (err) -+ goto ERR; ++ if (ctx->enc) ++ err = crypto_akcipher_encrypt(req); ++ else ++ err = crypto_akcipher_decrypt(req); + -+ /* reset the SW state */ -+ nisttrng_reset_state(state); ++ akcipher_request_set_tfm(req, cipher); + -+ 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) ++static bool aspeed_rsa_need_fallback(struct akcipher_request *req) +{ -+ int err = 0; -+ u32 tmp; ++ struct crypto_akcipher *cipher = crypto_akcipher_reqtfm(req); ++ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(cipher); + -+ DEBUG(">> %s cmd %d\n", __func__, rnc_ctrl_cmd); ++ return ctx->key.n_sz > ASPEED_RSA_MAX_KEY_LEN; ++} + -+ 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; ++static int aspeed_rsa_handle_queue(struct aspeed_rsss_dev *rsss_dev, ++ struct akcipher_request *req) ++{ ++ if (aspeed_rsa_need_fallback(req)) { ++ RSSS_DBG(rsss_dev, "SW fallback\n"); ++ return aspeed_rsa_do_fallback(req); + } + -+ if (!state->config.build_cfg0.edu_present) { -+ DEBUG(">> edu not present\n"); -+ err = -1; -+ goto ERR; -+ } ++ return crypto_transfer_akcipher_request_to_engine(rsss_dev->crypt_engine_rsa, req); ++} + -+ 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)); ++static int aspeed_rsa_do_request(struct crypto_engine *engine, void *areq) ++{ ++ struct akcipher_request *req = akcipher_request_cast(areq); ++ struct crypto_akcipher *cipher = crypto_akcipher_reqtfm(req); ++ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(cipher); ++ struct aspeed_rsss_dev *rsss_dev = ctx->rsss_dev; ++ struct aspeed_engine_rsa *rsa_engine; + -+ state->status.edu_vstat.rnc_enabled = 1; ++ rsa_engine = &rsss_dev->rsa_engine; ++ rsa_engine->req = req; ++ rsa_engine->flags |= CRYPTO_FLAGS_BUSY; + -+ } 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)); ++ return ctx->trigger(rsss_dev); ++} ++ ++static int aspeed_rsa_complete(struct aspeed_rsss_dev *rsss_dev, int err) ++{ ++ struct aspeed_engine_rsa *rsa_engine = &rsss_dev->rsa_engine; ++ struct akcipher_request *req = rsa_engine->req; ++ ++ rsa_engine->flags &= ~CRYPTO_FLAGS_BUSY; ++ ++ crypto_finalize_akcipher_request(rsss_dev->crypt_engine_rsa, req, err); + -+ 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) ++/* ++ * Copy Data to SRAM buffer for engine used. ++ */ ++static void aspeed_rsa_sg_copy_to_buffer(struct aspeed_rsss_dev *rsss_dev, ++ void __iomem *buf, struct scatterlist *src, ++ size_t nbytes) +{ -+ int err = 0; -+ u32 tmp, t; ++ RSSS_DBG(rsss_dev, "src len:%zu\n", nbytes); + -+ t = NIST_TRNG_RETRY_MAX; ++ memset(data_rev, 0, SRAM_BLOCK_SIZE); ++ memset(data, 0, SRAM_BLOCK_SIZE); + -+ DEBUG(">> %s starts...\n", __func__); ++ scatterwalk_map_and_copy(data, src, 0, nbytes, 0); + -+ do { -+ tmp = pdu_io_read32(state->base + NIST_TRNG_EDU_STAT); -+ } while ((!NIST_TRNG_EDU_STAT_FIFO_FULL(tmp)) && --t); ++ hexdump("data", data, nbytes); ++ for (int i = 0; i < nbytes; i++) ++ data_rev[nbytes - i - 1] = data[i]; + -+ if (t) { -+ err = CRYPTO_OK; -+ } else { -+ DEBUG("wait_on_fifo_full: failed timeout: %08lx\n", -+ (unsigned long)tmp); -+ err = CRYPTO_TIMEOUT; -+ goto ERR; ++ /* align 8 bytes */ ++ memcpy_toio(buf, data_rev, (nbytes + 7) & ~(8 - 1)); ++} ++ ++/* ++ * Copy Exp/Mod to SRAM buffer for engine used. ++ * ++ * Params: ++ * - mode 0 : Exponential ++ * - mode 1 : Modulus ++ */ ++static int aspeed_rsa_ctx_copy(struct aspeed_rsss_dev *rsss_dev, void __iomem *dst, ++ const u8 *src, size_t nbytes, ++ enum aspeed_rsa_key_mode mode) ++{ ++ RSSS_DBG(rsss_dev, "nbytes:%zu, mode:%d\n", nbytes, mode); ++ ++ if (nbytes > ASPEED_RSA_MAX_KEY_LEN) ++ return -ENOMEM; ++ ++ memset(data, 0, SRAM_BLOCK_SIZE); ++ ++ /* Remove leading zeros */ ++ while (nbytes > 0 && src[0] == 0) { ++ src++; ++ nbytes--; + } + -+ERR: -+ DEBUG("--- Return %s, err = %i\n", __func__, err); -+ return err; -+} -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 2026-04-08 18:03:48.285705777 +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) ++ for (int i = 0; i < nbytes; i++) ++ data[nbytes - i - 1] = src[i]; + -+#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; ++ /* align 8 bytes */ ++ memcpy_toio(dst, data, (nbytes + 7) & ~(8 - 1)); + -+ 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 }, -+}; ++ return nbytes * 8; ++} + - 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) ++static int aspeed_rsa_transfer(struct aspeed_rsss_dev *rsss_dev) +{ -+ struct aspeed_kcs_bmc *kcs_aspeed = to_aspeed_kcs_bmc(kcs_bmc); -+ int rc; -+ u8 str; ++ struct aspeed_engine_rsa *rsa_engine = &rsss_dev->rsa_engine; ++ struct akcipher_request *req = rsa_engine->req; ++ struct scatterlist *out_sg = req->dst; ++ size_t nbytes = req->dst_len; ++ u8 data[SRAM_BLOCK_SIZE]; ++ u32 val; + -+ /* 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); -+ } -+ } ++ RSSS_DBG(rsss_dev, "nbytes:%zu\n", nbytes); + -+ if (mask & KCS_BMC_EVENT_TYPE_IBF) { -+ const bool enable = !!(state & KCS_BMC_EVENT_TYPE_IBF); ++ /* Set SRAM access control - CPU */ ++ val = ast_rsss_read(rsss_dev, ASPEED_RSSS_CTRL); ++ ast_rsss_write(rsss_dev, val | SRAM_AHB_MODE_CPU, ASPEED_RSSS_CTRL); + -+ 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; -+ } -+ } ++ for (int i = 0; i < nbytes; i++) ++ data[nbytes - i - 1] = readb(rsa_engine->sram_data + i); ++ ++ scatterwalk_map_and_copy(data, out_sg, 0, nbytes, 1); ++ ++ return aspeed_rsa_complete(rsss_dev, 0); +} + -+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, -+}; ++#ifdef RSSS_RSA_POLLING_MODE ++static int aspeed_rsa_wait_complete(struct aspeed_rsss_dev *rsss_dev) ++{ ++ struct aspeed_engine_rsa *rsa_engine = &rsss_dev->rsa_engine; ++ u32 sts; ++ int ret; + - /* -- * 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; - } - --static void aspeed_kcs_enable_channel(struct kcs_bmc_device *kcs_bmc, bool enable) -+static int aspeed_kcs_enable_channel(struct aspeed_kcs_bmc *kcs_aspeed, bool enable) - { -- struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc); -- -- switch (kcs_bmc->channel) { -+ switch (kcs_aspeed->hw_inst) { -+ case 0: -+ regmap_update_bits(kcs_aspeed->map, HICR0, HICR0_LPC1E, enable * HICR0_LPC1E); -+ break; - case 1: -- regmap_update_bits(priv->map, LPC_HICR0, LPC_HICR0_LPC1E, enable * LPC_HICR0_LPC1E); -- return; -+ regmap_update_bits(kcs_aspeed->map, HICR0, HICR0_LPC2E, enable * HICR0_LPC2E); -+ break; - case 2: -- regmap_update_bits(priv->map, LPC_HICR0, LPC_HICR0_LPC2E, enable * LPC_HICR0_LPC2E); -- return; -+ regmap_update_bits(kcs_aspeed->map, HICR0, HICR0_LPC3E, enable * HICR0_LPC3E); -+ regmap_update_bits(kcs_aspeed->map, HICR4, HICR4_KCSENBL, enable * HICR4_KCSENBL); -+ break; - case 3: -- regmap_update_bits(priv->map, LPC_HICR0, LPC_HICR0_LPC3E, enable * LPC_HICR0_LPC3E); -- regmap_update_bits(priv->map, LPC_HICR4, -- LPC_HICR4_KCSENBL, enable * LPC_HICR4_KCSENBL); -- return; -- case 4: -- regmap_update_bits(priv->map, LPC_HICRB, LPC_HICRB_LPC4E, enable * LPC_HICRB_LPC4E); -- return; -+ regmap_update_bits(kcs_aspeed->map, HICRB, HICRB_LPC4E, enable * HICRB_LPC4E); -+ break; - default: -- pr_warn("%s: Unsupported channel: %d", __func__, kcs_bmc->channel); -- return; -+ return -EINVAL; - } ++ ret = readl_poll_timeout(rsss_dev->regs + ASPEED_RSA_ENG_STS, sts, ++ ((sts & RSA_STS) == 0x0), ++ ASPEED_RSSS_POLLING_TIME, ++ ASPEED_RSSS_TIMEOUT * 10); ++ if (ret) { ++ dev_err(rsss_dev->dev, "RSA wrong engine status\n"); ++ return -EIO; ++ } + -+ return 0; - } - - static void aspeed_kcs_check_obe(struct timer_list *timer) - { -- struct aspeed_kcs_bmc *priv = container_of(timer, struct aspeed_kcs_bmc, obe.timer); -+ struct aspeed_kcs_bmc *kcs_aspeed = container_of(timer, struct aspeed_kcs_bmc, obe.timer); - unsigned long flags; - u8 str; - -- spin_lock_irqsave(&priv->obe.lock, flags); -- if (priv->obe.remove) { -- spin_unlock_irqrestore(&priv->obe.lock, flags); -+ spin_lock_irqsave(&kcs_aspeed->obe.lock, flags); -+ if (kcs_aspeed->obe.remove) { -+ spin_unlock_irqrestore(&kcs_aspeed->obe.lock, flags); - return; - } - -- str = aspeed_kcs_inb(&priv->kcs_bmc, priv->kcs_bmc.ioreg.str); -+ str = aspeed_kcs_inb(&kcs_aspeed->kcs_bmc, kcs_aspeed->kcs_bmc.ioreg.str); - if (str & KCS_BMC_STR_OBF) { -- mod_timer(timer, jiffies + OBE_POLL_PERIOD); -- spin_unlock_irqrestore(&priv->obe.lock, flags); -+ mod_timer(timer, jiffies + KCS_OBE_POLL_PERIOD); -+ spin_unlock_irqrestore(&kcs_aspeed->obe.lock, flags); - return; - } -- spin_unlock_irqrestore(&priv->obe.lock, flags); -- -- kcs_bmc_handle_event(&priv->kcs_bmc); --} -- --static void aspeed_kcs_irq_mask_update(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 state) --{ -- struct aspeed_kcs_bmc *priv = 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, -- &priv->kcs_bmc, priv->kcs_bmc.ioreg.str); -- /* Time for the slow path? */ -- if (rc == -ETIMEDOUT) -- mod_timer(&priv->obe.timer, jiffies + OBE_POLL_PERIOD); -- } else { -- del_timer(&priv->obe.timer); -- } -- } -+ spin_unlock_irqrestore(&kcs_aspeed->obe.lock, flags); - -- if (mask & KCS_BMC_EVENT_TYPE_IBF) { -- const bool enable = !!(state & KCS_BMC_EVENT_TYPE_IBF); -- -- switch (kcs_bmc->channel) { -- case 1: -- regmap_update_bits(priv->map, LPC_HICR2, LPC_HICR2_IBFIE1, -- enable * LPC_HICR2_IBFIE1); -- return; -- case 2: -- regmap_update_bits(priv->map, LPC_HICR2, LPC_HICR2_IBFIE2, -- enable * LPC_HICR2_IBFIE2); -- return; -- case 3: -- regmap_update_bits(priv->map, LPC_HICR2, LPC_HICR2_IBFIE3, -- enable * LPC_HICR2_IBFIE3); -- return; -- case 4: -- regmap_update_bits(priv->map, LPC_HICRB, LPC_HICRB_IBFIE4, -- enable * LPC_HICRB_IBFIE4); -- return; -- default: -- pr_warn("%s: Unsupported channel: %d", __func__, kcs_bmc->channel); -- return; -- } -- } -+ kcs_bmc_handle_event(&kcs_aspeed->kcs_bmc); - } - --static const struct kcs_bmc_device_ops aspeed_kcs_ops = { -- .irq_mask_update = aspeed_kcs_irq_mask_update, -- .io_inputb = aspeed_kcs_inb, -- .io_outputb = aspeed_kcs_outb, -- .io_updateb = aspeed_kcs_updateb, --}; -- --static irqreturn_t aspeed_kcs_irq(int irq, void *arg) -+static irqreturn_t aspeed_kcs_isr(int irq, void *arg) - { - struct kcs_bmc_device *kcs_bmc = arg; - - return kcs_bmc_handle_event(kcs_bmc); - } - --static int aspeed_kcs_config_downstream_irq(struct kcs_bmc_device *kcs_bmc, -- struct platform_device *pdev) -+static int aspeed_kcs_probe(struct platform_device *pdev) - { -- struct device *dev = &pdev->dev; -- int irq; -+ struct aspeed_kcs_bmc *kcs_aspeed; -+ struct kcs_bmc_device *kcs_bmc; -+ struct device *dev; -+ const __be32 *reg; -+ int i, rc, chan; - -- irq = platform_get_irq(pdev, 0); -- if (irq < 0) -- return irq; -- -- return devm_request_irq(dev, irq, aspeed_kcs_irq, IRQF_SHARED, -- dev_name(dev), kcs_bmc); --} -+ dev = &pdev->dev; - --static const struct kcs_ioreg ast_kcs_bmc_ioregs[KCS_CHANNEL_MAX] = { -- { .idr = LPC_IDR1, .odr = LPC_ODR1, .str = LPC_STR1 }, -- { .idr = LPC_IDR2, .odr = LPC_ODR2, .str = LPC_STR2 }, -- { .idr = LPC_IDR3, .odr = LPC_ODR3, .str = LPC_STR3 }, -- { .idr = LPC_IDR4, .odr = LPC_ODR4, .str = LPC_STR4 }, --}; -+ kcs_aspeed = devm_kzalloc(dev, sizeof(*kcs_aspeed), GFP_KERNEL); -+ if (!kcs_aspeed) -+ return -ENOMEM; - --static int aspeed_kcs_of_get_channel(struct platform_device *pdev) --{ -- struct device_node *np; -- struct kcs_ioreg ioreg; -- const __be32 *reg; -- int i; -+ kcs_bmc = &kcs_aspeed->kcs_bmc; -+ kcs_bmc->ops = &aspeed_kcs_ops; -+ kcs_bmc->dev = dev; - -- np = pdev->dev.of_node; -+ kcs_aspeed->map = syscon_node_to_regmap(pdev->dev.parent->of_node); -+ if (IS_ERR(kcs_aspeed->map)) { -+ dev_err(&pdev->dev, "cannot get regmap\n"); -+ return -ENODEV; ++ ret = readl_poll_timeout(rsss_dev->regs + ASPEED_RSSS_INT_STS, sts, ++ ((sts & RSA_INT_DONE) == RSA_INT_DONE), ++ ASPEED_RSSS_POLLING_TIME, ++ ASPEED_RSSS_TIMEOUT); ++ if (ret) { ++ dev_err(rsss_dev->dev, "RSA wrong interrupt status\n"); ++ return -EIO; + } - -- /* Don't translate addresses, we want offsets for the regmaps */ -- reg = of_get_address(np, 0, NULL, NULL); -- if (!reg) -- return -EINVAL; -- ioreg.idr = be32_to_cpup(reg); -+ kcs_aspeed->irq = platform_get_irq(pdev, 0); -+ if (kcs_aspeed->irq < 0) { -+ dev_err(dev, "cannot get IRQ number\n"); -+ return kcs_aspeed->irq; ++ ++ ast_rsss_write(rsss_dev, sts, ASPEED_RSSS_INT_STS); ++ ++ RSSS_DBG(rsss_dev, "irq sts:0x%x\n", sts); ++ ++ if (sts & RSA_INT_DONE) { ++ /* Stop RSA engine */ ++ ast_rsss_write(rsss_dev, 0, ASPEED_RSA_TRIGGER); ++ ++ if (rsa_engine->flags & CRYPTO_FLAGS_BUSY) ++ tasklet_schedule(&rsa_engine->done_task); ++ else ++ dev_err(rsss_dev->dev, "RSA no active requests.\n"); + } - -- reg = of_get_address(np, 1, NULL, NULL); -- if (!reg) -- return -EINVAL; -- ioreg.odr = be32_to_cpup(reg); -+ reg = of_get_address(dev->of_node, 0, NULL, NULL); -+ if (!reg) { -+ dev_err(dev, "cannot get IDR\n"); -+ return -ENODEV; ++ ++ return 0; ++} ++#endif ++ ++static int aspeed_rsa_trigger(struct aspeed_rsss_dev *rsss_dev) ++{ ++ struct aspeed_engine_rsa *rsa_engine = &rsss_dev->rsa_engine; ++ struct akcipher_request *req = rsa_engine->req; ++ struct crypto_akcipher *cipher; ++ struct aspeed_rsa_ctx *ctx; ++ int ne, nm; ++ u32 val; ++ ++ RSSS_DBG(rsss_dev, "\n"); ++ ++ cipher = crypto_akcipher_reqtfm(req); ++ ctx = akcipher_tfm_ctx(cipher); ++ ++ if (!ctx->n || !ctx->n_sz) { ++ dev_err(rsss_dev->dev, "%s: key n is not set\n", __func__); ++ return -EINVAL; + } - -- reg = of_get_address(np, 2, NULL, NULL); -- if (!reg) -- return -EINVAL; -- ioreg.str = be32_to_cpup(reg); -+ kcs_bmc->ioreg.idr = be32_to_cpup(reg); - -- for (i = 0; i < ARRAY_SIZE(ast_kcs_bmc_ioregs); i++) { -- if (!memcmp(&ast_kcs_bmc_ioregs[i], &ioreg, sizeof(ioreg))) -- return i + 1; -+ reg = of_get_address(dev->of_node, 1, NULL, NULL); -+ if (!reg) { -+ dev_err(dev, "cannot get ODR\n"); -+ return -ENODEV; - } -- return -EINVAL; --} - --static int --aspeed_kcs_of_get_io_address(struct platform_device *pdev, u32 addrs[2]) --{ -- int rc; -+ kcs_bmc->ioreg.odr = be32_to_cpup(reg); - -- rc = of_property_read_variable_u32_array(pdev->dev.of_node, -- "aspeed,lpc-io-reg", -- addrs, 1, 2); -- if (rc < 0) { -- dev_err(&pdev->dev, "No valid 'aspeed,lpc-io-reg' configured\n"); -- return rc; -+ reg = of_get_address(dev->of_node, 2, NULL, NULL); -+ if (!reg) { -+ dev_err(dev, "cannot get STR\n"); -+ return -ENODEV; - } - -- if (addrs[0] > 0xffff) { -- dev_err(&pdev->dev, "Invalid data address in 'aspeed,lpc-io-reg'\n"); -- return -EINVAL; -+ kcs_bmc->ioreg.str = be32_to_cpup(reg); + -+ for (i = 0; i < KCS_HW_INSTANCE_NUM; ++i) { -+ if (aspeed_kcs_ioregs[i].idr == kcs_bmc->ioreg.idr && -+ aspeed_kcs_ioregs[i].odr == kcs_bmc->ioreg.odr && -+ aspeed_kcs_ioregs[i].str == kcs_bmc->ioreg.str) { -+ kcs_aspeed->hw_inst = i; -+ break; -+ } - } - -- if (rc == 2 && addrs[1] > 0xffff) { -- dev_err(&pdev->dev, "Invalid status address in 'aspeed,lpc-io-reg'\n"); -+ if (i >= KCS_HW_INSTANCE_NUM) { -+ dev_err(dev, "invalid IDR/ODR/STR register\n"); - return -EINVAL; - } - -- return rc; --} -- --static int aspeed_kcs_probe(struct platform_device *pdev) --{ -- struct kcs_bmc_device *kcs_bmc; -- struct aspeed_kcs_bmc *priv; -- struct device_node *np; -- bool have_upstream_irq; -- u32 upstream_irq[2]; -- int rc, channel; -- int nr_addrs; -- u32 addrs[2]; -- -- np = pdev->dev.of_node->parent; -- if (!of_device_is_compatible(np, "aspeed,ast2400-lpc-v2") && -- !of_device_is_compatible(np, "aspeed,ast2500-lpc-v2") && -- !of_device_is_compatible(np, "aspeed,ast2600-lpc-v2")) { -- dev_err(&pdev->dev, "unsupported LPC device binding\n"); -+ rc = of_property_read_u32(dev->of_node, "kcs-io-addr", &kcs_aspeed->io_addr); -+ if (rc || kcs_aspeed->io_addr > (USHRT_MAX - 1)) { -+ dev_err(dev, "invalid IO address\n"); - return -ENODEV; - } - -- channel = aspeed_kcs_of_get_channel(pdev); -- if (channel < 0) -- return channel; -- -- nr_addrs = aspeed_kcs_of_get_io_address(pdev, addrs); -- if (nr_addrs < 0) -- return nr_addrs; -- -- np = pdev->dev.of_node; -- rc = of_property_read_u32_array(np, "aspeed,lpc-interrupts", upstream_irq, 2); -- if (rc && rc != -EINVAL) -- return -EINVAL; -- -- have_upstream_irq = !rc; -+ rc = of_property_read_u32(dev->of_node, "kcs-channel", &chan); -+ if (rc) { -+ chan = ida_alloc(&aspeed_kcs_bmc_ida, GFP_KERNEL); -+ if (chan < 0) { -+ dev_err(dev, "cannot allocate ID for KCS channel\n"); -+ return chan; -+ } -+ } - -- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -- if (!priv) -- return -ENOMEM; -+ kcs_bmc->channel = chan; - -- kcs_bmc = &priv->kcs_bmc; -- kcs_bmc->dev = &pdev->dev; -- kcs_bmc->channel = channel; -- kcs_bmc->ioreg = ast_kcs_bmc_ioregs[channel - 1]; -- kcs_bmc->ops = &aspeed_kcs_ops; -+ rc = of_property_read_u32_array(dev->of_node, "kcs-upstream-serirq", (u32 *)&kcs_aspeed->sirq, 2); -+ if (rc) { -+ kcs_aspeed->sirq.type = IRQ_TYPE_NONE; -+ } else { -+ if (kcs_aspeed->sirq.id > 15) { -+ dev_err(dev, "invalid SerIRQ number, expected sirq <= 15\n"); -+ return -EINVAL; -+ } - -- priv->map = syscon_node_to_regmap(pdev->dev.parent->of_node); -- if (IS_ERR(priv->map)) { -- dev_err(&pdev->dev, "Couldn't get regmap\n"); -- return -ENODEV; -+ if (kcs_aspeed->sirq.type != IRQ_TYPE_LEVEL_HIGH && -+ kcs_aspeed->sirq.type != IRQ_TYPE_LEVEL_LOW) { -+ dev_err(dev, "invalid SerIRQ type, expected IRQ_TYPE_LEVEL_HIGH/LOW only\n"); -+ return -EINVAL; -+ } - } - -- spin_lock_init(&priv->obe.lock); -- priv->obe.remove = false; -- timer_setup(&priv->obe.timer, aspeed_kcs_check_obe, 0); -+ timer_setup(&kcs_aspeed->obe.timer, aspeed_kcs_check_obe, 0); -+ spin_lock_init(&kcs_aspeed->obe.lock); -+ kcs_aspeed->obe.remove = false; - -- rc = aspeed_kcs_set_address(kcs_bmc, addrs, nr_addrs); -+ aspeed_kcs_irq_mask_update(kcs_bmc, (KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE), 0); -+ -+ rc = aspeed_kcs_config_io_address(kcs_aspeed); - if (rc) - return rc; - -- /* Host to BMC IRQ */ -- rc = aspeed_kcs_config_downstream_irq(kcs_bmc, pdev); -+ rc = aspeed_kcs_config_upstream_serirq(kcs_aspeed); - if (rc) - return rc; - -- /* BMC to Host IRQ */ -- if (have_upstream_irq) { -- rc = aspeed_kcs_config_upstream_irq(priv, upstream_irq[0], upstream_irq[1]); -- if (rc < 0) -- return rc; -- } else { -- priv->upstream_irq.mode = aspeed_kcs_irq_none; -+ rc = devm_request_irq(dev, kcs_aspeed->irq, aspeed_kcs_isr, IRQF_SHARED, -+ dev_name(dev), kcs_bmc); -+ if (rc) { -+ dev_err(dev, "cannot request IRQ\n"); -+ return rc; - } - -- platform_set_drvdata(pdev, priv); -+ platform_set_drvdata(pdev, kcs_aspeed); - -- aspeed_kcs_irq_mask_update(kcs_bmc, (KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE), 0); -- aspeed_kcs_enable_channel(kcs_bmc, true); -+ rc = aspeed_kcs_enable_channel(kcs_aspeed, true); -+ if (rc) { -+ dev_err(dev, "cannot enable channel %d: %d\n", -+ kcs_bmc->channel, rc); -+ return rc; -+ } - -- rc = kcs_bmc_add_device(&priv->kcs_bmc); -+ rc = kcs_bmc_add_device(kcs_bmc); - if (rc) { -- dev_warn(&pdev->dev, "Failed to register channel %d: %d\n", kcs_bmc->channel, rc); -+ dev_warn(dev, "cannot register channel %d: %d\n", -+ kcs_bmc->channel, rc); - return rc; - } - -- dev_info(&pdev->dev, "Initialised channel %d at 0x%x\n", -- kcs_bmc->channel, addrs[0]); -+ dev_info(dev, "Initialised channel %d at IO address 0x%x\n", -+ kcs_bmc->channel, kcs_aspeed->io_addr); - - return 0; - } - - static void aspeed_kcs_remove(struct platform_device *pdev) - { -- struct aspeed_kcs_bmc *priv = platform_get_drvdata(pdev); -- struct kcs_bmc_device *kcs_bmc = &priv->kcs_bmc; -+ struct aspeed_kcs_bmc *kcs_aspeed = platform_get_drvdata(pdev); -+ struct kcs_bmc_device *kcs_bmc = &kcs_aspeed->kcs_bmc; - - kcs_bmc_remove_device(kcs_bmc); - -- aspeed_kcs_enable_channel(kcs_bmc, false); -+ aspeed_kcs_enable_channel(kcs_aspeed, false); - aspeed_kcs_irq_mask_update(kcs_bmc, (KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE), 0); - - /* Make sure it's proper dead */ -- spin_lock_irq(&priv->obe.lock); -- priv->obe.remove = true; -- spin_unlock_irq(&priv->obe.lock); -- del_timer_sync(&priv->obe.timer); -+ spin_lock_irq(&kcs_aspeed->obe.lock); -+ kcs_aspeed->obe.remove = true; -+ spin_unlock_irq(&kcs_aspeed->obe.lock); -+ del_timer_sync(&kcs_aspeed->obe.timer); - } - --static const struct of_device_id ast_kcs_bmc_match[] = { -- { .compatible = "aspeed,ast2400-kcs-bmc-v2" }, -- { .compatible = "aspeed,ast2500-kcs-bmc-v2" }, -+static const struct of_device_id aspeed_kcs_bmc_match[] = { -+ { .compatible = "aspeed,ast2400-kcs-bmc" }, -+ { .compatible = "aspeed,ast2500-kcs-bmc" }, - { .compatible = "aspeed,ast2600-kcs-bmc" }, - { } - }; --MODULE_DEVICE_TABLE(of, ast_kcs_bmc_match); -+MODULE_DEVICE_TABLE(of, aspeed_kcs_bmc_match); - --static struct platform_driver ast_kcs_bmc_driver = { -+static struct platform_driver aspeed_kcs_bmc_driver = { - .driver = { -- .name = DEVICE_NAME, -- .of_match_table = ast_kcs_bmc_match, -+ .name = DEVICE_NAME, -+ .of_match_table = aspeed_kcs_bmc_match, - }, -- .probe = aspeed_kcs_probe, -- .remove_new = aspeed_kcs_remove, -+ .probe = aspeed_kcs_probe, -+ .remove = aspeed_kcs_remove, - }; --module_platform_driver(ast_kcs_bmc_driver); -+module_platform_driver(aspeed_kcs_bmc_driver); - - MODULE_LICENSE("GPL v2"); - MODULE_AUTHOR("Haiyue Wang "); - 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 2026-04-08 18:03:32.729989759 +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. ++ /* Set SRAM access control - CPU */ ++ val = ast_rsss_read(rsss_dev, ASPEED_RSSS_CTRL); ++ ast_rsss_write(rsss_dev, val | SRAM_AHB_MODE_CPU, ASPEED_RSSS_CTRL); + - 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 2026-04-08 18:03:37.201908196 +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 2026-04-08 18:03:47.783714949 +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 }, - [ASPEED_CLK_GATE_USBPORT2CLK] = { 7, 3, "usb-port2-gate", NULL, 0 }, /* USB2.0 Host port 2 */ -- [ASPEED_CLK_GATE_LCLK] = { 8, 5, "lclk-gate", NULL, 0 }, /* LPC */ -+ [ASPEED_CLK_GATE_LCLK] = { 8, 5, "lclk-gate", NULL, CLK_IS_CRITICAL }, /* LPC */ - [ASPEED_CLK_GATE_USBUHCICLK] = { 9, 15, "usb-uhci-gate", NULL, 0 }, /* USB1.1 (requires port 2 enabled) */ - [ASPEED_CLK_GATE_D1CLK] = { 10, 13, "d1clk-gate", NULL, 0 }, /* GFX CRT */ - [ASPEED_CLK_GATE_YCLK] = { 13, 4, "yclk-gate", NULL, 0 }, /* HAC */ - [ASPEED_CLK_GATE_USBPORT1CLK] = { 14, 14, "usb-port1-gate", NULL, 0 }, /* USB2 hub/USB2 host port 1/USB1.1 dev */ -- [ASPEED_CLK_GATE_UART1CLK] = { 15, -1, "uart1clk-gate", "uart", 0 }, /* UART1 */ -- [ASPEED_CLK_GATE_UART2CLK] = { 16, -1, "uart2clk-gate", "uart", 0 }, /* UART2 */ -+ [ASPEED_CLK_GATE_UART1CLK] = { 15, -1, "uart1clk-gate", "uart", CLK_IS_CRITICAL }, /* UART1 */ -+ [ASPEED_CLK_GATE_UART2CLK] = { 16, -1, "uart2clk-gate", "uart", CLK_IS_CRITICAL }, /* UART2 */ - [ASPEED_CLK_GATE_UART5CLK] = { 17, -1, "uart5clk-gate", "uart", 0 }, /* UART5 */ -- [ASPEED_CLK_GATE_ESPICLK] = { 19, -1, "espiclk-gate", NULL, 0 }, /* eSPI */ -+ [ASPEED_CLK_GATE_ESPICLK] = { 19, -1, "espiclk-gate", NULL, CLK_IS_CRITICAL }, /* eSPI */ - [ASPEED_CLK_GATE_MAC1CLK] = { 20, 11, "mac1clk-gate", "mac", 0 }, /* MAC1 */ - [ASPEED_CLK_GATE_MAC2CLK] = { 21, 12, "mac2clk-gate", "mac", 0 }, /* MAC2 */ - [ASPEED_CLK_GATE_RSACLK] = { 24, -1, "rsaclk-gate", NULL, 0 }, /* RSA */ -@@ -278,6 +278,7 @@ - [ASPEED_RESET_PECI] = 10, - [ASPEED_RESET_I2C] = 2, - [ASPEED_RESET_AHB] = 1, -+ [ASPEED_RESET_VIDEO] = 6, - - /* - * 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 2026-04-08 18:03:47.788714857 +0000 -@@ -0,0 +1,809 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+// Copyright ASPEED Technology ++ memset_io(rsa_engine->sram_exp, 0, SRAM_BLOCK_SIZE); ++ memset_io(rsa_engine->sram_mod, 0, SRAM_BLOCK_SIZE); ++ memset_io(rsa_engine->sram_data, 0, SRAM_BLOCK_SIZE); + -+#include -+#include -+#include -+#include ++ /* Copy source data to SRAM buffer */ ++ aspeed_rsa_sg_copy_to_buffer(rsss_dev, rsa_engine->sram_data, ++ req->src, req->src_len); + -+#include -+#include ++ nm = aspeed_rsa_ctx_copy(rsss_dev, rsa_engine->sram_mod, ctx->n, ++ ctx->n_sz, ASPEED_RSA_MOD_MODE); + -+#define AST1700_CLK_25MHZ 25000000 -+#define AST1700_CLK_24MHZ 24000000 -+#define AST1700_CLK_192MHZ 192000000 -+/* IO Die */ -+#define AST1700_CLK_STOP 0x240 -+#define AST1700_CLK_STOP2 0x260 -+#define AST1700_CLK_SEL1 0x280 -+#define AST1700_CLK_SEL2 0x284 -+#define UXCLK_MASK GENMASK(1, 0) -+#define HUXCLK_MASK GENMASK(4, 3) -+#define AST1700_HPLL_PARAM 0x300 -+#define AST1700_APLL_PARAM 0x310 -+#define AST1700_DPLL_PARAM 0x320 -+#define AST1700_UXCLK_CTRL 0x330 -+#define AST1700_HUXCLK_CTRL 0x334 ++ /* Set dst len as modulus size */ ++ req->dst_len = nm / 8; + -+#define CREATE_CLK_NAME(id, suffix) kasprintf(GFP_KERNEL, "ast1700_%d-%s", id, suffix) ++ if (ctx->enc) { ++ if (!ctx->e || !ctx->e_sz) { ++ dev_err(rsss_dev->dev, "%s: key e is not set\n", ++ __func__); ++ return -EINVAL; ++ } ++ /* Copy key e to SRAM buffer */ ++ ne = aspeed_rsa_ctx_copy(rsss_dev, rsa_engine->sram_exp, ++ ctx->e, ctx->e_sz, ++ ASPEED_RSA_EXP_MODE); ++ } else { ++ if (!ctx->d || !ctx->d_sz) { ++ dev_err(rsss_dev->dev, "%s: key d is not set\n", ++ __func__); ++ return -EINVAL; ++ } ++ /* Copy key d to SRAM buffer */ ++ ne = aspeed_rsa_ctx_copy(rsss_dev, rsa_engine->sram_exp, ++ ctx->key.d, ctx->key.d_sz, ++ ASPEED_RSA_EXP_MODE); ++ } + -+static DEFINE_IDA(ast1700_clk_ida); ++ hexdump("exp", rsa_engine->sram_exp, ctx->e_sz); ++ hexdump("mod", rsa_engine->sram_mod, ctx->n_sz); ++ hexdump("data", rsa_engine->sram_data, req->src_len); + -+/* Globally visible clocks */ -+static DEFINE_SPINLOCK(ast1700_clk_lock); ++ rsa_engine->resume = aspeed_rsa_transfer; + -+/* Division of RGMII Clock */ -+static const struct clk_div_table ast1700_rgmii_div_table[] = { -+ { 0x0, 4 }, -+ { 0x1, 4 }, -+ { 0x2, 6 }, -+ { 0x3, 8 }, -+ { 0x4, 10 }, -+ { 0x5, 12 }, -+ { 0x6, 14 }, -+ { 0x7, 16 }, -+ { 0 } -+}; ++ ast_rsss_write(rsss_dev, (ne << 16) + nm, ++ ASPEED_RSA_KEY_INFO); + -+/* Division of RMII Clock */ -+static const struct clk_div_table ast1700_rmii_div_table[] = { -+ { 0x0, 8 }, -+ { 0x1, 8 }, -+ { 0x2, 12 }, -+ { 0x3, 16 }, -+ { 0x4, 20 }, -+ { 0x5, 24 }, -+ { 0x6, 28 }, -+ { 0x7, 32 }, -+ { 0 } -+}; ++ /* Set SRAM access control - Engine */ ++ val = ast_rsss_read(rsss_dev, ASPEED_RSSS_CTRL); ++ ast_rsss_write(rsss_dev, val & ~SRAM_AHB_MODE_CPU, ASPEED_RSSS_CTRL); + -+/* Division of HCLK/SDIO/MAC/apll_divn CLK */ -+static const struct clk_div_table ast1700_clk_div_table[] = { -+ { 0x0, 2 }, -+ { 0x1, 2 }, -+ { 0x2, 3 }, -+ { 0x3, 4 }, -+ { 0x4, 5 }, -+ { 0x5, 6 }, -+ { 0x6, 7 }, -+ { 0x7, 8 }, -+ { 0 } -+}; ++ /* Trigger RSA engines */ ++ ast_rsss_write(rsss_dev, RSA_TRIGGER, ASPEED_RSA_TRIGGER); + -+/* Division of PCLK/EMMC CLK */ -+static const struct clk_div_table ast1700_clk_div_table2[] = { -+ { 0x0, 2 }, -+ { 0x1, 4 }, -+ { 0x2, 6 }, -+ { 0x3, 8 }, -+ { 0x4, 10 }, -+ { 0x5, 12 }, -+ { 0x6, 14 }, -+ { 0x7, 16 }, -+ { 0 } -+}; ++#ifdef RSSS_RSA_POLLING_MODE ++ return aspeed_rsa_wait_complete(rsss_dev); ++#else ++ return 0; ++#endif ++} + -+static struct clk_hw *AST1700_calc_uclk(int id, u32 val) ++static int aspeed_rsa_enc(struct akcipher_request *req) +{ -+ unsigned int mult, div; -+ -+ /* UARTCLK = UXCLK * R / (N * 2) */ -+ u32 r = val & 0xff; -+ u32 n = (val >> 8) & 0x3ff; ++ struct crypto_akcipher *cipher = crypto_akcipher_reqtfm(req); ++ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(cipher); ++ struct aspeed_rsss_dev *rsss_dev = ctx->rsss_dev; + -+ mult = r; -+ div = n * 2; ++ ctx->trigger = aspeed_rsa_trigger; ++ ctx->enc = 1; + -+ return clk_hw_register_fixed_factor(NULL, CREATE_CLK_NAME(id, "uartxclk"), -+ CREATE_CLK_NAME(id, "uxclk"), 0, mult, div); -+}; ++ return aspeed_rsa_handle_queue(rsss_dev, req); ++} + -+static struct clk_hw *AST1700_calc_huclk(int id, u32 val) ++static int aspeed_rsa_dec(struct akcipher_request *req) +{ -+ unsigned int mult, div; -+ -+ /* UARTCLK = UXCLK * R / (N * 2) */ -+ u32 r = val & 0xff; -+ u32 n = (val >> 8) & 0x3ff; ++ struct crypto_akcipher *cipher = crypto_akcipher_reqtfm(req); ++ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(cipher); ++ struct aspeed_rsss_dev *rsss_dev = ctx->rsss_dev; + -+ mult = r; -+ div = n * 2; ++ ctx->trigger = aspeed_rsa_trigger; ++ ctx->enc = 0; + -+ return clk_hw_register_fixed_factor(NULL, CREATE_CLK_NAME(id, "huartxclk"), -+ CREATE_CLK_NAME(id, "huxclk"), 0, mult, div); -+}; ++ return aspeed_rsa_handle_queue(rsss_dev, req); ++} + -+static struct clk_hw *AST1700_calc_pll(const char *name, const char *parent_name, u32 val) ++static u8 *aspeed_rsa_key_copy(u8 *src, size_t len) +{ -+ unsigned int mult, div; -+ -+ if (val & BIT(24)) { -+ /* Pass through mode */ -+ mult = 1; -+ div = 1; -+ } else { -+ /* F = 25Mhz * [(M + 1) / (n + 1)] / (p + 1) */ -+ u32 m = val & 0x1fff; -+ u32 n = (val >> 13) & 0x3f; -+ u32 p = (val >> 19) & 0xf; -+ -+ mult = (m + 1) / (n + 1); -+ div = (p + 1); -+ } -+ return clk_hw_register_fixed_factor(NULL, name, parent_name, 0, mult, div); ++ return kmemdup(src, len, GFP_KERNEL); +} + -+static int AST1700_clk_is_enabled(struct clk_hw *hw) ++static int aspeed_rsa_set_n(struct aspeed_rsa_ctx *ctx, u8 *value, ++ size_t len) +{ -+ struct clk_gate *gate = to_clk_gate(hw); -+ u32 clk = BIT(gate->bit_idx); -+ u32 reg; -+ -+ reg = readl(gate->reg); ++ ctx->n_sz = len; ++ ctx->n = aspeed_rsa_key_copy(value, len); ++ if (!ctx->n) ++ return -ENOMEM; + -+ return !(reg & clk); ++ return 0; +} + -+static int AST1700_clk_enable(struct clk_hw *hw) ++static int aspeed_rsa_set_e(struct aspeed_rsa_ctx *ctx, u8 *value, ++ size_t len) +{ -+ struct clk_gate *gate = to_clk_gate(hw); -+ u32 clk = BIT(gate->bit_idx); -+ -+ if (readl(gate->reg) & clk) -+ writel(clk, gate->reg + 0x04); ++ ctx->e_sz = len; ++ ctx->e = aspeed_rsa_key_copy(value, len); ++ if (!ctx->e) ++ return -ENOMEM; + + return 0; +} + -+static void AST1700_clk_disable(struct clk_hw *hw) ++static int aspeed_rsa_set_d(struct aspeed_rsa_ctx *ctx, u8 *value, ++ size_t len) +{ -+ struct clk_gate *gate = to_clk_gate(hw); -+ u32 clk = BIT(gate->bit_idx); ++ ctx->d_sz = len; ++ ctx->d = aspeed_rsa_key_copy(value, len); ++ if (!ctx->d) ++ return -ENOMEM; + -+ /* Clock is set to enable, so use write to set register */ -+ writel(clk, gate->reg); ++ return 0; +} + -+static const struct clk_ops AST1700_clk_gate_ops = { -+ .enable = AST1700_clk_enable, -+ .disable = AST1700_clk_disable, -+ .is_enabled = AST1700_clk_is_enabled, -+}; -+ -+static struct clk_hw *AST1700_clk_hw_register_gate(struct device *dev, const char *name, -+ const char *parent_name, unsigned long flags, -+ void __iomem *reg, u8 clock_idx, -+ u8 clk_gate_flags, spinlock_t *lock) ++static void aspeed_rsa_key_free(struct aspeed_rsa_ctx *ctx) +{ -+ struct clk_gate *gate; -+ struct clk_hw *hw; -+ struct clk_init_data init; -+ int ret = -EINVAL; ++ kfree_sensitive(ctx->n); ++ kfree_sensitive(ctx->e); ++ kfree_sensitive(ctx->d); ++ ctx->n_sz = 0; ++ ctx->e_sz = 0; ++ ctx->d_sz = 0; ++} + -+ gate = kzalloc(sizeof(*gate), GFP_KERNEL); -+ if (!gate) -+ return ERR_PTR(-ENOMEM); ++static int aspeed_rsa_setkey(struct crypto_akcipher *tfm, const void *key, ++ unsigned int keylen, int priv) ++{ ++ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); ++ struct aspeed_rsss_dev *rsss_dev = ctx->rsss_dev; ++ int ret; + -+ init.name = name; -+ init.ops = &AST1700_clk_gate_ops; -+ init.flags = flags; -+ init.parent_names = parent_name ? &parent_name : NULL; -+ init.num_parents = parent_name ? 1 : 0; ++ RSSS_DBG(rsss_dev, "\n"); + -+ gate->reg = reg; -+ gate->bit_idx = clock_idx; -+ gate->flags = clk_gate_flags; -+ gate->lock = lock; -+ gate->hw.init = &init; ++ if (priv) ++ ret = rsa_parse_priv_key(&ctx->key, key, keylen); ++ else ++ ret = rsa_parse_pub_key(&ctx->key, key, keylen); + -+ hw = &gate->hw; -+ ret = clk_hw_register(dev, hw); + if (ret) { -+ kfree(gate); -+ hw = ERR_PTR(ret); ++ dev_err(rsss_dev->dev, "rsss parse key failed, ret:0x%x\n", ++ ret); ++ return ret; + } + -+ return hw; -+} ++ /* Aspeed engine supports up to 4096 bits, ++ * Use software fallback instead. ++ */ ++ if (ctx->key.n_sz > ASPEED_RSA_MAX_KEY_LEN) ++ return 0; + -+struct ast1700_reset { -+ void __iomem *base; -+ struct reset_controller_dev rcdev; -+}; ++ 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; + -+#define to_rc_data(p) container_of(p, struct ast1700_reset, rcdev) ++ 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; + -+static int ast1700_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) -+{ -+ struct ast1700_reset *rc = to_rc_data(rcdev); -+ u32 rst = BIT(id % 32); -+ u32 reg = id >= 32 ? 0x220 : 0x200; ++ 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; ++ } + -+ writel(rst, rc->base + reg); + return 0; ++ ++err: ++ dev_err(rsss_dev->dev, "rsss set key failed\n"); ++ aspeed_rsa_key_free(ctx); ++ ++ return ret; +} + -+static int ast1700_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) ++static int aspeed_rsa_set_pub_key(struct crypto_akcipher *tfm, ++ const void *key, ++ unsigned int keylen) +{ -+ struct ast1700_reset *rc = to_rc_data(rcdev); -+ u32 rst = BIT(id % 32); -+ u32 reg = id >= 32 ? 0x220 : 0x200; ++ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); ++ int ret; + -+ /* Use set to clear register */ -+ writel(rst, rc->base + reg + 0x04); -+ return 0; ++ ret = crypto_akcipher_set_pub_key(ctx->fallback_tfm, key, keylen); ++ if (ret) ++ return ret; ++ ++ return aspeed_rsa_setkey(tfm, key, keylen, 0); +} + -+static int ast1700_reset_status(struct reset_controller_dev *rcdev, unsigned long id) ++static int aspeed_rsa_set_priv_key(struct crypto_akcipher *tfm, ++ const void *key, ++ unsigned int keylen) +{ -+ struct ast1700_reset *rc = to_rc_data(rcdev); -+ u32 rst = BIT(id % 32); -+ u32 reg = id >= 32 ? 0x220 : 0x200; ++ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); ++ int ret; + -+ return (readl(rc->base + reg) & rst); ++ ret = crypto_akcipher_set_priv_key(ctx->fallback_tfm, key, keylen); ++ if (ret) ++ return ret; ++ ++ return aspeed_rsa_setkey(tfm, key, keylen, 1); +} + -+static const struct reset_control_ops ast1700_reset_ops = { -+ .assert = ast1700_reset_assert, -+ .deassert = ast1700_reset_deassert, -+ .status = ast1700_reset_status, -+}; ++static unsigned int aspeed_rsa_max_size(struct crypto_akcipher *tfm) ++{ ++ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); + -+static const char *const sdclk_sel0[] = { -+ "ast1700_0-hpll_divn", -+ "ast1700_0-apll_divn", -+}; ++ if (ctx->key.n_sz > ASPEED_RSA_MAX_KEY_LEN) ++ return crypto_akcipher_maxsize(ctx->fallback_tfm); + -+static const char *const sdclk_sel1[] = { -+ "ast1700_1-hpll_divn", -+ "ast1700_1-apll_divn", -+}; ++ return ctx->n_sz; ++} + -+static const char *const uartclk_sel0[] = { -+ "ast1700_0-uartxclk", -+ "ast1700_0-huartxclk", -+}; ++static int aspeed_rsa_init_tfm(struct crypto_akcipher *tfm) ++{ ++ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); ++ struct akcipher_alg *alg = crypto_akcipher_alg(tfm); ++ const char *name = crypto_tfm_alg_name(&tfm->base); ++ struct aspeed_rsss_alg *rsa_alg; + -+static const char *const uartclk_sel1[] = { -+ "ast1700_1-uartxclk", -+ "ast1700_1-huartxclk", -+}; ++ rsa_alg = container_of(alg, struct aspeed_rsss_alg, alg.akcipher.base); + -+static const char *const uxclk_sel0[] = { -+ "ast1700_0-apll_div4", -+ "ast1700_0-apll_div2", -+ "ast1700_0-apll", -+ "ast1700_0-hpll", -+}; ++ ctx->rsss_dev = rsa_alg->rsss_dev; + -+static const char *const uxclk_sel1[] = { -+ "ast1700_1-apll_div4", -+ "ast1700_1-apll_div2", -+ "ast1700_1-apll", -+ "ast1700_1-hpll", -+}; ++ ctx->fallback_tfm = crypto_alloc_akcipher(name, 0, CRYPTO_ALG_ASYNC | ++ CRYPTO_ALG_NEED_FALLBACK); ++ if (IS_ERR(ctx->fallback_tfm)) { ++ dev_err(ctx->rsss_dev->dev, "ERROR: Cannot allocate fallback for %s %ld\n", ++ name, PTR_ERR(ctx->fallback_tfm)); ++ return PTR_ERR(ctx->fallback_tfm); ++ } + -+static int AST1700_clk_init(struct device_node *ast1700_node) ++ return 0; ++} ++ ++static void aspeed_rsa_exit_tfm(struct crypto_akcipher *tfm) +{ -+ struct clk_hw_onecell_data *clk_data; -+ struct ast1700_reset *reset; -+ u32 uart_clk_source = 0; -+ void __iomem *clk_base; -+ struct clk_hw **clks; -+ struct clk_hw *hw; -+ u32 val; -+ int ret; ++ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); + -+ int id = ida_simple_get(&ast1700_clk_ida, 0, 0, GFP_KERNEL); ++ crypto_free_akcipher(ctx->fallback_tfm); ++} + -+ clk_base = of_iomap(ast1700_node, 0); -+ WARN_ON(!clk_base); ++struct aspeed_rsss_alg aspeed_rsss_algs_rsa = { ++ .type = ASPEED_ALGO_TYPE_AKCIPHER, ++ .alg.akcipher.base = { ++ .encrypt = aspeed_rsa_enc, ++ .decrypt = aspeed_rsa_dec, ++ .sign = aspeed_rsa_dec, ++ .verify = aspeed_rsa_enc, ++ .set_pub_key = aspeed_rsa_set_pub_key, ++ .set_priv_key = aspeed_rsa_set_priv_key, ++ .max_size = aspeed_rsa_max_size, ++ .init = aspeed_rsa_init_tfm, ++ .exit = aspeed_rsa_exit_tfm, ++ .base = { ++ .cra_name = "rsa", ++ .cra_driver_name = "aspeed-rsa", ++ .cra_priority = 300, ++ .cra_flags = CRYPTO_ALG_TYPE_AKCIPHER | ++ CRYPTO_ALG_ASYNC | ++ CRYPTO_ALG_KERN_DRIVER_ONLY | ++ CRYPTO_ALG_NEED_FALLBACK, ++ .cra_module = THIS_MODULE, ++ .cra_ctxsize = sizeof(struct aspeed_rsa_ctx), ++ }, ++ }, ++ .alg.akcipher.op = { ++ .do_one_request = aspeed_rsa_do_request, ++ }, ++}; + -+ clk_data = kzalloc(struct_size(clk_data, hws, AST1700_NUM_CLKS), GFP_KERNEL); -+ if (!clk_data) -+ return -ENOMEM; ++static void aspeed_rsa_done_task(unsigned long data) ++{ ++ struct aspeed_rsss_dev *rsss_dev = (struct aspeed_rsss_dev *)data; ++ struct aspeed_engine_rsa *rsa_engine = &rsss_dev->rsa_engine; + -+ clk_data->num = AST1700_NUM_CLKS; -+ clks = clk_data->hws; ++ (void)rsa_engine->resume(rsss_dev); ++} + -+ reset = kzalloc(sizeof(*reset), GFP_KERNEL); -+ if (!reset) -+ return -ENOMEM; ++void aspeed_rsss_rsa_exit(struct aspeed_rsss_dev *rsss_dev) ++{ ++ struct aspeed_engine_rsa *rsa_engine = &rsss_dev->rsa_engine; + -+ reset->base = clk_base; ++ crypto_engine_exit(rsss_dev->crypt_engine_rsa); ++ tasklet_kill(&rsa_engine->done_task); ++} + -+ reset->rcdev.owner = THIS_MODULE; -+ reset->rcdev.nr_resets = AST1700_RESET_NUMS; -+ reset->rcdev.ops = &ast1700_reset_ops; -+ reset->rcdev.of_node = ast1700_node; ++int aspeed_rsss_rsa_init(struct aspeed_rsss_dev *rsss_dev) ++{ ++ struct aspeed_engine_rsa *rsa_engine; ++ u32 val; ++ int rc; + -+ ret = reset_controller_register(&reset->rcdev); -+ if (ret) { -+ pr_err("soc1 failed to register reset controller\n"); -+ return ret; -+ } -+ /* -+ * Ast1700 A0 workaround: -+ * I3C reset should assert all of the I3C controllers simultaneously. -+ * Otherwise, it may lead to failure in accessing I3C registers. -+ */ -+ if (!(readl(clk_base) & BIT(16))) { -+ for (int i = AST1700_RESET_I3C0; i <= AST1700_RESET_I3C15; i++) -+ ast1700_reset_assert(&reset->rcdev, i); ++ rc = reset_control_deassert(rsss_dev->reset_rsa); ++ if (rc) { ++ dev_err(rsss_dev->dev, "Deassert RSA reset failed\n"); ++ goto end; + } + -+ hw = clk_hw_register_fixed_rate(NULL, CREATE_CLK_NAME(id, "clkin"), NULL, 0, AST1700_CLK_25MHZ); -+ if (IS_ERR(hw)) -+ return PTR_ERR(hw); -+ clks[AST1700_CLKIN] = hw; ++ rsa_engine = &rsss_dev->rsa_engine; + -+ /* HPLL 1000Mhz */ -+ val = readl(clk_base + AST1700_HPLL_PARAM); -+ clks[AST1700_CLK_HPLL] = AST1700_calc_pll(CREATE_CLK_NAME(id, "hpll"), CREATE_CLK_NAME(id, "clkin"), val); ++ /* Initialize crypto hardware engine structure for RSA */ ++ rsss_dev->crypt_engine_rsa = crypto_engine_alloc_init(rsss_dev->dev, true); ++ if (!rsss_dev->crypt_engine_rsa) { ++ rc = -ENOMEM; ++ goto end; ++ } + -+ /* HPLL 800Mhz */ -+ val = readl(clk_base + AST1700_APLL_PARAM); -+ clks[AST1700_CLK_APLL] = AST1700_calc_pll(CREATE_CLK_NAME(id, "apll"), CREATE_CLK_NAME(id, "clkin"), val); ++ rc = crypto_engine_start(rsss_dev->crypt_engine_rsa); ++ if (rc) ++ goto err_engine_rsa_start; + -+ clks[AST1700_CLK_APLL_DIV2] = -+ clk_hw_register_fixed_factor(NULL, CREATE_CLK_NAME(id, "apll_div2"), CREATE_CLK_NAME(id, "apll"), 0, 1, 2); ++ tasklet_init(&rsa_engine->done_task, aspeed_rsa_done_task, ++ (unsigned long)rsss_dev); + -+ clks[AST1700_CLK_APLL_DIV4] = -+ clk_hw_register_fixed_factor(NULL, CREATE_CLK_NAME(id, "apll_div4"), CREATE_CLK_NAME(id, "apll"), 0, 1, 4); ++ rsa_engine->sram_exp = rsss_dev->regs + SRAM_OFFSET_EXP; ++ rsa_engine->sram_mod = rsss_dev->regs + SRAM_OFFSET_MOD; ++ rsa_engine->sram_data = rsss_dev->regs + SRAM_OFFSET_DATA; + -+ val = readl(clk_base + AST1700_DPLL_PARAM); -+ clks[AST1700_CLK_DPLL] = AST1700_calc_pll(CREATE_CLK_NAME(id, "dpll"), CREATE_CLK_NAME(id, "clkin"), val); ++ /* Set SRAM for RSA operation */ ++ ast_rsss_write(rsss_dev, RSA_OPERATION, ASPEED_RSSS_CTRL); + -+ /* uxclk mux selection */ -+ clks[AST1700_CLK_UXCLK] = -+ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uxclk"), -+ (id == 0) ? uxclk_sel0 : uxclk_sel1, -+ (id == 0) ? ARRAY_SIZE(uxclk_sel0) : ARRAY_SIZE(uxclk_sel1), -+ 0, clk_base + AST1700_CLK_SEL2, -+ 0, 2, 0, &ast1700_clk_lock); ++ /* Self-test */ ++ rc = aspeed_rsa_self_test(rsss_dev); ++ if (rc) ++ goto err_engine_rsa_start; + -+ val = readl(clk_base + AST1700_UXCLK_CTRL); -+ clks[AST1700_CLK_UARTX] = AST1700_calc_uclk(id, val); ++ /* Enable RSA interrupt */ ++ val = ast_rsss_read(rsss_dev, ASPEED_RSSS_INT_EN); ++ ast_rsss_write(rsss_dev, val | RSA_INT_EN, ASPEED_RSSS_INT_EN); + -+ /* huxclk mux selection */ -+ clks[AST1700_CLK_HUXCLK] = -+ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "huxclk"), -+ (id == 0) ? uxclk_sel0 : uxclk_sel1, -+ (id == 0) ? ARRAY_SIZE(uxclk_sel0) : ARRAY_SIZE(uxclk_sel1), -+ 0, clk_base + AST1700_CLK_SEL2, -+ 3, 2, 0, &ast1700_clk_lock); ++ dev_info(rsss_dev->dev, "Aspeed RSSS RSA initialized\n"); + -+ val = readl(clk_base + AST1700_HUXCLK_CTRL); -+ clks[AST1700_CLK_HUARTX] = AST1700_calc_huclk(id, val); ++ return 0; + -+ /* AHB CLK = 200Mhz */ -+ clks[AST1700_CLK_AHB] = -+ clk_hw_register_divider_table(NULL, CREATE_CLK_NAME(id, "ahb"), -+ CREATE_CLK_NAME(id, "hpll"), -+ 0, clk_base + AST1700_CLK_SEL2, -+ 20, 3, 0, ast1700_clk_div_table, &ast1700_clk_lock); ++err_engine_rsa_start: ++ crypto_engine_exit(rsss_dev->crypt_engine_rsa); ++end: ++ return rc; ++} +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 +@@ -0,0 +1,188 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright 2023 Aspeed Technology Inc. ++ */ + -+ /* APB CLK = 100Mhz */ -+ clks[AST1700_CLK_APB] = -+ clk_hw_register_divider_table(NULL, CREATE_CLK_NAME(id, "apb"), -+ CREATE_CLK_NAME(id, "hpll"), -+ 0, clk_base + AST1700_CLK_SEL1, -+ 18, 3, 0, ast1700_clk_div_table2, &ast1700_clk_lock); ++#include ++#include ++#include ++#include ++#include "aspeed-rsss.h" + -+ //rmii -+ clks[AST1700_CLK_RMII] = -+ clk_hw_register_divider_table(NULL, CREATE_CLK_NAME(id, "rmii"), -+ CREATE_CLK_NAME(id, "hpll"), -+ 0, clk_base + AST1700_CLK_SEL2, -+ 21, 3, 0, ast1700_rmii_div_table, &ast1700_clk_lock); ++static struct aspeed_rsss_alg *aspeed_rsss_algs[] = { ++ &aspeed_rsss_algs_rsa, ++ &aspeed_rsss_algs_sha3_224, ++ &aspeed_rsss_algs_sha3_256, ++ &aspeed_rsss_algs_sha3_384, ++ &aspeed_rsss_algs_sha3_512, ++}; + -+ //rgmii -+ clks[AST1700_CLK_RGMII] = -+ clk_hw_register_divider_table(NULL, CREATE_CLK_NAME(id, "rgmii"), -+ CREATE_CLK_NAME(id, "hpll"), -+ 0, clk_base + AST1700_CLK_SEL2, -+ 25, 3, 0, ast1700_rgmii_div_table, &ast1700_clk_lock); ++static void aspeed_rsss_register(struct aspeed_rsss_dev *rsss_dev) ++{ ++ char *cra_name; ++ int rc; + -+ //mac hclk -+ clks[AST1700_CLK_MACHCLK] = -+ clk_hw_register_divider_table(NULL, CREATE_CLK_NAME(id, "machclk"), -+ CREATE_CLK_NAME(id, "hpll"), -+ 0, clk_base + AST1700_CLK_SEL2, -+ 29, 3, 0, ast1700_clk_div_table, &ast1700_clk_lock); ++ for (int i = 0; i < ARRAY_SIZE(aspeed_rsss_algs); i++) { ++ aspeed_rsss_algs[i]->rsss_dev = rsss_dev; ++ if (aspeed_rsss_algs[i]->type == ASPEED_ALGO_TYPE_AKCIPHER) { ++ rc = crypto_engine_register_akcipher(&aspeed_rsss_algs[i]->alg.akcipher); ++ cra_name = aspeed_rsss_algs[i]->alg.akcipher.base.base.cra_name; + -+ clks[AST1700_CLK_GATE_LCLK0] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "lclk0-gate"), NULL, -+ CLK_IS_CRITICAL, clk_base + AST1700_CLK_STOP, -+ 0, 0, &ast1700_clk_lock); ++ } else if (aspeed_rsss_algs[i]->type == ASPEED_ALGO_TYPE_AHASH) { ++ rc = crypto_engine_register_ahash(&aspeed_rsss_algs[i]->alg.ahash); ++ cra_name = aspeed_rsss_algs[i]->alg.ahash.base.halg.base.cra_name; ++ } + -+ clks[AST1700_CLK_GATE_LCLK0] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "lclk1-gate"), NULL, -+ CLK_IS_CRITICAL, clk_base + AST1700_CLK_STOP, -+ 1, 0, &ast1700_clk_lock); ++ if (rc) ++ dev_warn(rsss_dev->dev, "Failed to register [%d] %s(0x%x)\n", i, cra_name, rc); ++ } ++} + -+ clks[AST1700_CLK_GATE_ESPI0CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "espi0clk-gate"), NULL, -+ CLK_IS_CRITICAL, clk_base + AST1700_CLK_STOP, -+ 2, 0, &ast1700_clk_lock); ++static void aspeed_rsss_unregister(struct aspeed_rsss_dev *rsss_dev) ++{ ++ for (int i = 0; i < ARRAY_SIZE(aspeed_rsss_algs); i++) { ++ if (aspeed_rsss_algs[i]->type == ASPEED_ALGO_TYPE_AKCIPHER) ++ crypto_engine_unregister_akcipher(&aspeed_rsss_algs[i]->alg.akcipher); + -+ clks[AST1700_CLK_GATE_ESPI1CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "espi1clk-gate"), NULL, -+ CLK_IS_CRITICAL, clk_base + AST1700_CLK_STOP, -+ 3, 0, &ast1700_clk_lock); ++ else if (aspeed_rsss_algs[i]->type == ASPEED_ALGO_TYPE_AHASH) ++ crypto_engine_unregister_ahash(&aspeed_rsss_algs[i]->alg.ahash); ++ } ++} + -+ //sd pll divn -+ clks[AST1700_CLK_HPLL_DIVN] = -+ clk_hw_register_divider_table(NULL, CREATE_CLK_NAME(id, "hpll_divn"), -+ CREATE_CLK_NAME(id, "hpll"), -+ 0, clk_base + AST1700_CLK_SEL2, -+ 20, 3, 0, ast1700_clk_div_table, &ast1700_clk_lock); ++/* RSSS interrupt service routine. */ ++static irqreturn_t aspeed_rsss_irq(int irq, void *dev) ++{ ++ struct aspeed_rsss_dev *rsss_dev = (struct aspeed_rsss_dev *)dev; ++ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; ++ struct aspeed_engine_rsa *rsa_engine = &rsss_dev->rsa_engine; ++ u32 sts; + -+ clks[AST1700_CLK_APLL_DIVN] = -+ clk_hw_register_divider_table(NULL, CREATE_CLK_NAME(id, "apll_divn"), -+ CREATE_CLK_NAME(id, "apll"), -+ 0, clk_base + AST1700_CLK_SEL2, -+ 8, 3, 0, ast1700_clk_div_table, &ast1700_clk_lock); ++ sts = ast_rsss_read(rsss_dev, ASPEED_RSSS_INT_STS); ++ ast_rsss_write(rsss_dev, sts, ASPEED_RSSS_INT_STS); + -+ //sd clk -+ clks[AST1700_CLK_SDCLK] = -+ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "sdclk"), -+ (id == 0) ? sdclk_sel0 : sdclk_sel1, -+ (id == 0) ? ARRAY_SIZE(sdclk_sel0) : ARRAY_SIZE(sdclk_sel1), -+ 0, clk_base + AST1700_CLK_SEL1, -+ 13, 1, 0, &ast1700_clk_lock); ++ RSSS_DBG(rsss_dev, "irq sts:0x%x\n", sts); + -+ clks[AST1700_CLK_GATE_SDCLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "sdclk-gate"), -+ CREATE_CLK_NAME(id, "sdclk"), -+ 0, clk_base + AST1700_CLK_STOP, -+ 4, 0, &ast1700_clk_lock); ++ if (sts & RSA_INT_DONE) { ++ /* Stop RSA engine */ ++ ast_rsss_write(rsss_dev, 0, ASPEED_RSA_TRIGGER); + -+ clks[AST1700_CLK_GATE_REFCLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "io-refclk-gate"), NULL, -+ CLK_IS_CRITICAL, clk_base + AST1700_CLK_STOP, -+ 6, 0, &ast1700_clk_lock); ++ if (rsa_engine->flags & CRYPTO_FLAGS_BUSY) ++ tasklet_schedule(&rsa_engine->done_task); ++ else ++ dev_err(rsss_dev->dev, "RSA no active requests.\n"); ++ } + -+ clks[AST1700_CLK_GATE_LPCHCLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "lpchclk-gate"), NULL, -+ CLK_IS_CRITICAL, clk_base + AST1700_CLK_STOP, -+ 7, 0, &ast1700_clk_lock); ++ if (sts & SHA3_INT_DONE) { ++ if (sha3_engine->flags & CRYPTO_FLAGS_BUSY) ++ tasklet_schedule(&sha3_engine->done_task); ++ else ++ dev_err(rsss_dev->dev, "SHA3 no active requests.\n"); ++ } + -+ clks[AST1700_CLK_GATE_MAC0CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "mac0clk-gate"), NULL, -+ 0, clk_base + AST1700_CLK_STOP, -+ 8, 0, &ast1700_clk_lock); ++ return IRQ_HANDLED; ++} + -+ clks[AST1700_CLK_GATE_MAC1CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "mac1clk-gate"), NULL, -+ 0, clk_base + AST1700_CLK_STOP, -+ 9, 0, &ast1700_clk_lock); ++static const struct of_device_id aspeed_rsss_of_matches[] = { ++ { .compatible = "aspeed,ast2700-rsss", }, ++ {}, ++}; + -+ clks[AST1700_CLK_GATE_MAC2CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "mac2clk-gate"), NULL, -+ 0, clk_base + AST1700_CLK_STOP, -+ 10, 0, &ast1700_clk_lock); ++static int aspeed_rsss_probe(struct platform_device *pdev) ++{ ++ struct aspeed_rsss_dev *rsss_dev; ++ struct device *dev = &pdev->dev; ++ int rc; + -+ of_property_read_u32(ast1700_node, "uart-clk-source", &uart_clk_source); ++ rsss_dev = devm_kzalloc(dev, sizeof(struct aspeed_rsss_dev), ++ GFP_KERNEL); ++ if (!rsss_dev) ++ return -ENOMEM; + -+ if (uart_clk_source) { -+ val = readl(clk_base + AST1700_CLK_SEL1) & ~GENMASK(12, 0); -+ uart_clk_source &= GENMASK(12, 0); -+ writel(val | uart_clk_source, clk_base + AST1700_CLK_SEL1); -+ } ++ rsss_dev->dev = dev; + -+ //UART0 -+ clks[AST1700_CLK_UART0] = -+ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart0clk"), -+ (id == 0) ? uartclk_sel0 : uartclk_sel1, -+ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), -+ 0, clk_base + AST1700_CLK_SEL1, -+ 0, 1, 0, &ast1700_clk_lock); ++ platform_set_drvdata(pdev, rsss_dev); + -+ clks[AST1700_CLK_GATE_UART0CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart0clk-gate"), -+ CREATE_CLK_NAME(id, "uart0clk"), -+ 0, clk_base + AST1700_CLK_STOP, -+ 11, 0, &ast1700_clk_lock); ++ rsss_dev->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(rsss_dev->regs)) ++ return PTR_ERR(rsss_dev->regs); + -+ //UART1 -+ clks[AST1700_CLK_UART1] = -+ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart1clk"), -+ (id == 0) ? uartclk_sel0 : uartclk_sel1, -+ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), -+ 0, clk_base + AST1700_CLK_SEL1, -+ 1, 1, 0, &ast1700_clk_lock); ++ /* Get irq number and register it */ ++ rsss_dev->irq = platform_get_irq(pdev, 0); ++ if (rsss_dev->irq < 0) ++ return -ENXIO; + -+ clks[AST1700_CLK_GATE_UART1CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart1clk-gate"), -+ CREATE_CLK_NAME(id, "uart1clk"), -+ 0, clk_base + AST1700_CLK_STOP, -+ 12, 0, &ast1700_clk_lock); ++ rc = devm_request_irq(dev, rsss_dev->irq, aspeed_rsss_irq, 0, ++ dev_name(dev), rsss_dev); ++ if (rc) { ++ dev_err(dev, "Failed to request irq.\n"); ++ return rc; ++ } + -+ //UART2 -+ clks[AST1700_CLK_UART2] = -+ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart2clk"), -+ (id == 0) ? uartclk_sel0 : uartclk_sel1, -+ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), -+ 0, clk_base + AST1700_CLK_SEL1, -+ 2, 1, 0, &ast1700_clk_lock); ++ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); ++ if (rc) { ++ dev_warn(&pdev->dev, "No suitable DMA available\n"); ++ return rc; ++ } + -+ clks[AST1700_CLK_GATE_UART2CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart2clk-gate"), -+ CREATE_CLK_NAME(id, "uart2clk"), -+ 0, clk_base + AST1700_CLK_STOP, -+ 13, 0, &ast1700_clk_lock); ++ rsss_dev->clk = devm_clk_get_enabled(dev, NULL); ++ if (IS_ERR(rsss_dev->clk)) { ++ dev_err(dev, "Failed to get rsss clk\n"); ++ return PTR_ERR(rsss_dev->clk); ++ } + -+ //UART3 -+ clks[AST1700_CLK_UART3] = -+ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart3clk"), -+ (id == 0) ? uartclk_sel0 : uartclk_sel1, -+ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), -+ 0, clk_base + AST1700_CLK_SEL1, -+ 3, 1, 0, &ast1700_clk_lock); ++ rsss_dev->reset_rsa = devm_reset_control_get(dev, "rsa"); ++ if (IS_ERR(rsss_dev->reset_rsa)) { ++ dev_err(dev, "Failed to get rsa reset\n"); ++ return PTR_ERR(rsss_dev->reset_rsa); ++ } + -+ clks[AST1700_CLK_GATE_UART3CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart3clk-gate"), -+ CREATE_CLK_NAME(id, "uart3clk"), -+ 0, clk_base + AST1700_CLK_STOP, -+ 14, 0, &ast1700_clk_lock); ++ rsss_dev->reset_sha3 = devm_reset_control_get(dev, "sha3"); ++ if (IS_ERR(rsss_dev->reset_sha3)) { ++ dev_err(dev, "Failed to get sha3 reset\n"); ++ return PTR_ERR(rsss_dev->reset_sha3); ++ } + -+ clks[AST1700_CLK_GATE_I3C0CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c0clk-gate"), -+ CREATE_CLK_NAME(id, "ahb"), -+ 0, clk_base + AST1700_CLK_STOP, -+ 16, 0, &ast1700_clk_lock); ++ rc = aspeed_rsss_rsa_init(rsss_dev); ++ if (rc) { ++ dev_err(dev, "RSA init failed\n"); ++ return rc; ++ } + -+ clks[AST1700_CLK_GATE_I3C1CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c1clk-gate"), -+ CREATE_CLK_NAME(id, "ahb"), -+ 0, clk_base + AST1700_CLK_STOP, -+ 17, 0, &ast1700_clk_lock); ++ rc = aspeed_rsss_sha3_init(rsss_dev); ++ if (rc) { ++ dev_err(dev, "SHA3 init failed\n"); ++ return rc; ++ } + -+ clks[AST1700_CLK_GATE_I3C2CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c2clk-gate"), -+ CREATE_CLK_NAME(id, "ahb"), -+ 0, clk_base + AST1700_CLK_STOP, -+ 18, 0, &ast1700_clk_lock); ++ aspeed_rsss_register(rsss_dev); + -+ clks[AST1700_CLK_GATE_I3C3CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c3clk-gate"), -+ CREATE_CLK_NAME(id, "ahb"), -+ 0, clk_base + AST1700_CLK_STOP, -+ 19, 0, &ast1700_clk_lock); ++ dev_info(dev, "Aspeed RSSS Hardware Accelerator successfully registered\n"); + -+ clks[AST1700_CLK_GATE_I3C4CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c4clk-gate"), -+ CREATE_CLK_NAME(id, "ahb"), -+ 0, clk_base + AST1700_CLK_STOP, -+ 20, 0, &ast1700_clk_lock); ++ return 0; ++} + -+ clks[AST1700_CLK_GATE_I3C5CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c5clk-gate"), -+ CREATE_CLK_NAME(id, "ahb"), -+ 0, clk_base + AST1700_CLK_STOP, -+ 21, 0, &ast1700_clk_lock); ++static void aspeed_rsss_remove(struct platform_device *pdev) ++{ ++ struct aspeed_rsss_dev *rsss_dev = platform_get_drvdata(pdev); + -+ clks[AST1700_CLK_GATE_I3C6CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c6clk-gate"), -+ CREATE_CLK_NAME(id, "ahb"), -+ 0, clk_base + AST1700_CLK_STOP, -+ 22, 0, &ast1700_clk_lock); ++ aspeed_rsss_unregister(rsss_dev); ++ aspeed_rsss_rsa_exit(rsss_dev); ++ aspeed_rsss_sha3_exit(rsss_dev); ++} + -+ clks[AST1700_CLK_GATE_I3C7CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c7clk-gate"), -+ CREATE_CLK_NAME(id, "ahb"), -+ 0, clk_base + AST1700_CLK_STOP, -+ 23, 0, &ast1700_clk_lock); ++MODULE_DEVICE_TABLE(of, aspeed_rsss_of_matches); + -+ clks[AST1700_CLK_GATE_I3C8CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c8clk-gate"), -+ CREATE_CLK_NAME(id, "ahb"), -+ 0, clk_base + AST1700_CLK_STOP, -+ 24, 0, &ast1700_clk_lock); ++static struct platform_driver aspeed_rsss_driver = { ++ .probe = aspeed_rsss_probe, ++ .remove = aspeed_rsss_remove, ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = aspeed_rsss_of_matches, ++ }, ++}; + -+ clks[AST1700_CLK_GATE_I3C9CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c9clk-gate"), -+ CREATE_CLK_NAME(id, "ahb"), -+ 0, clk_base + AST1700_CLK_STOP, -+ 25, 0, &ast1700_clk_lock); ++module_platform_driver(aspeed_rsss_driver); + -+ clks[AST1700_CLK_GATE_I3C10CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c10clk-gate"), -+ CREATE_CLK_NAME(id, "ahb"), -+ 0, clk_base + AST1700_CLK_STOP, -+ 26, 0, &ast1700_clk_lock); ++MODULE_AUTHOR("Neal Liu "); ++MODULE_DESCRIPTION("ASPEED RSSS driver for multiple cryptographic engines"); ++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 +@@ -0,0 +1,275 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ + -+ clks[AST1700_CLK_GATE_I3C11CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c11clk-gate"), -+ CREATE_CLK_NAME(id, "ahb"), -+ 0, clk_base + AST1700_CLK_STOP, -+ 27, 0, &ast1700_clk_lock); ++#ifndef __ASPEED_RSSS_H__ ++#define __ASPEED_RSSS_H__ + -+ clks[AST1700_CLK_GATE_I3C12CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c12clk-gate"), -+ CREATE_CLK_NAME(id, "ahb"), -+ 0, clk_base + AST1700_CLK_STOP, -+ 28, 0, &ast1700_clk_lock); ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ clks[AST1700_CLK_GATE_I3C13CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c13clk-gate"), -+ CREATE_CLK_NAME(id, "ahb"), -+ 0, clk_base + AST1700_CLK_STOP, -+ 29, 0, &ast1700_clk_lock); ++#ifdef CONFIG_CRYPTO_DEV_ASPEED_DEBUG ++#define RSSS_DBG(d, fmt, ...) \ ++ dev_info((d)->dev, "%s() " fmt, __func__, ##__VA_ARGS__) ++#else ++#define RSSS_DBG(d, fmt, ...) \ ++ dev_dbg((d)->dev, "%s() " fmt, __func__, ##__VA_ARGS__) ++#endif + -+ clks[AST1700_CLK_GATE_I3C14CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c14clk-gate"), -+ CREATE_CLK_NAME(id, "ahb"), -+ 0, clk_base + AST1700_CLK_STOP, -+ 30, 0, &ast1700_clk_lock); ++/***************************** ++ * * ++ * RSSS register definitions * ++ * * ++ * ***************************/ ++#define ASPEED_RSSS_INT_STS 0xc00 /* RSSS interrupt status */ ++#define ASPEED_RSSS_INT_EN 0xc04 /* RSSS interrupt enable */ ++#define ASPEED_RSSS_CTRL 0xc08 /* RSSS generic control */ ++#define ASPEED_RSA_TRIGGER 0xe00 /* RSA Engine Control: trigger */ ++#define ASPEED_RSA_KEY_INFO 0xe08 /* RSA Exp/Mod Key Length (Bits) */ ++#define ASPEED_RSA_ENG_STS 0xe0c /* RSA Engine Status */ + -+ clks[AST1700_CLK_GATE_I3C15CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "i3c15clk-gate"), -+ CREATE_CLK_NAME(id, "ahb"), -+ 0, clk_base + AST1700_CLK_STOP, -+ 31, 0, &ast1700_clk_lock); ++#define ASPEED_SHA3_CMD 0xe80 ++#define ASPEED_SHA3_SRC_LO 0xe84 ++#define ASPEED_SHA3_SRC_HI 0xe88 ++#define ASPEED_SHA3_SRC_LEN 0xe8c ++#define ASPEED_SHA3_DST_LO 0xe90 ++#define ASPEED_SHA3_DST_HI 0xe94 ++#define ASPEED_SHA3_BUSY_STS 0xe98 ++#define ASPEED_SHA3_ENG_STS 0xe9c + -+ /*clk stop 2 */ -+ //UART5 -+ clks[AST1700_CLK_UART5] = -+ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart5clk"), -+ (id == 0) ? uartclk_sel0 : uartclk_sel1, -+ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), -+ 0, clk_base + AST1700_CLK_SEL1, -+ 5, 1, 0, &ast1700_clk_lock); ++/* RSSS interrupt status */ ++#define SM4_INT_DONE BIT(3) ++#define SM3_INT_DONE BIT(2) ++#define SHA3_INT_DONE BIT(1) ++#define RSA_INT_DONE BIT(0) + -+ clks[AST1700_CLK_GATE_UART5CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart5clk-gate"), -+ CREATE_CLK_NAME(id, "uart5clk"), -+ 0, clk_base + AST1700_CLK_STOP2, -+ 0, 0, &ast1700_clk_lock); ++/* RSSS interrupt enable */ ++#define SM4_INT_EN BIT(3) ++#define SM3_INT_EN BIT(2) ++#define SHA3_INT_EN BIT(1) ++#define RSA_INT_EN BIT(0) + -+ //UART6 -+ clks[AST1700_CLK_UART6] = -+ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart6clk"), -+ (id == 0) ? uartclk_sel0 : uartclk_sel1, -+ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), -+ 0, clk_base + AST1700_CLK_SEL1, -+ 6, 1, 0, &ast1700_clk_lock); ++/* RSSS generic control */ ++#define RSA_OPERATION (BIT(18) | BIT(19)) ++#define SRAM_AHB_MODE_CPU BIT(16) ++#define SRAM_AHB_MODE_ENGINE 0x0 ++#define SRAM_BUFF_PD (BIT(5) | BIT(4)) ++#define SM4_DISABLE BIT(3) ++#define SM3_DISABLE BIT(2) ++#define SHA3_DISABLE BIT(1) + -+ clks[AST1700_CLK_GATE_UART6CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart6clk-gate"), -+ CREATE_CLK_NAME(id, "uart6clk"), -+ 0, clk_base + AST1700_CLK_STOP2, -+ 1, 0, &ast1700_clk_lock); ++/* RSA trigger */ ++#define RSA_TRIGGER BIT(0) + -+ //UART7 -+ clks[AST1700_CLK_UART7] = -+ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart7clk"), -+ (id == 0) ? uartclk_sel0 : uartclk_sel1, -+ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), -+ 0, clk_base + AST1700_CLK_SEL1, -+ 7, 1, 0, &ast1700_clk_lock); ++/* RSA key len */ ++#define RSA_E_BITS_LEN(x) ((x) << 16) ++#define RSA_M_BITS_LEN(x) (x) + -+ clks[AST1700_CLK_GATE_UART7CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart7clk-gate"), -+ CREATE_CLK_NAME(id, "uart7clk"), -+ 0, clk_base + AST1700_CLK_STOP2, -+ 2, 0, &ast1700_clk_lock); ++#define RSA_STS (BIT(0) | BIT(1)) + -+ //UART8 -+ clks[AST1700_CLK_UART8] = -+ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart8clk"), -+ (id == 0) ? uartclk_sel0 : uartclk_sel1, -+ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), -+ 0, clk_base + AST1700_CLK_SEL1, -+ 8, 1, 0, &ast1700_clk_lock); ++/* RSA SRAM */ ++#define SRAM_OFFSET_EXP 0x0 ++#define SRAM_OFFSET_MOD 0x400 ++#define SRAM_OFFSET_DATA 0x800 ++#define SRAM_BLOCK_SIZE 0x400 + -+ clks[AST1700_CLK_GATE_UART8CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart8clk-gate"), -+ CREATE_CLK_NAME(id, "uart8clk"), -+ 0, clk_base + AST1700_CLK_STOP2, -+ 3, 0, &ast1700_clk_lock); ++#define ASPEED_RSA_MAX_KEY_LEN 512 /* RSA maximum key length (Bytes) */ + -+ //UART9 -+ clks[AST1700_CLK_UART9] = -+ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart9clk"), -+ (id == 0) ? uartclk_sel0 : uartclk_sel1, -+ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), -+ 0, clk_base + AST1700_CLK_SEL1, -+ 9, 1, 0, &ast1700_clk_lock); ++#define CRYPTO_FLAGS_BUSY BIT(1) + -+ clks[AST1700_CLK_GATE_UART9CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart9clk-gate"), -+ CREATE_CLK_NAME(id, "uart9clk"), -+ 0, clk_base + AST1700_CLK_STOP2, -+ 4, 0, &ast1700_clk_lock); ++/* SHA3 command */ ++#define SHA3_CMD_TRIG BIT(31) ++#define SHA3_CMD_MODE_224 (0x0 << 28) ++#define SHA3_CMD_MODE_256 (0x1 << 28) ++#define SHA3_CMD_MODE_384 (0x2 << 28) ++#define SHA3_CMD_MODE_512 (0x3 << 28) ++#define SHA3_CMD_MODE_S128 (0x4 << 28) ++#define SHA3_CMD_MODE_S256 (0x5 << 28) ++#define SHA3_CMD_HW_PAD BIT(27) ++#define SHA3_CMD_ACC_FINAL BIT(26) ++#define SHA3_CMD_ACC BIT(25) ++#define SHA3_CMD_SG_MODE BIT(24) ++#define SHA3_CMD_IN_RST BIT(21) ++#define SHA3_CMD_OUT_RST BIT(20) ++#define SHA3_CMD_OUT_LEN(x) ((x) & 0x1ffff) + -+ //UART10 -+ clks[AST1700_CLK_UART10] = -+ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart10clk"), -+ (id == 0) ? uartclk_sel0 : uartclk_sel1, -+ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), -+ 0, clk_base + AST1700_CLK_SEL1, -+ 10, 1, 0, &ast1700_clk_lock); ++#define SHA3_FLAGS_SHA224 BIT(0) ++#define SHA3_FLAGS_SHA256 BIT(1) ++#define SHA3_FLAGS_SHA384 BIT(2) ++#define SHA3_FLAGS_SHA512 BIT(3) ++#define SHA3_FLAGS_FINUP BIT(0xa) ++#define SHA3_FLAGS_MASK (0xff) + -+ clks[AST1700_CLK_GATE_UART10CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart10clk-gate"), -+ CREATE_CLK_NAME(id, "uart10clk"), -+ 0, clk_base + AST1700_CLK_STOP2, -+ 5, 0, &ast1700_clk_lock); ++#define SHA3_STS BIT(0) + -+ //UART11 -+ clks[AST1700_CLK_UART11] = -+ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart11clk"), -+ (id == 0) ? uartclk_sel0 : uartclk_sel1, -+ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), -+ 0, clk_base + AST1700_CLK_SEL1, -+ 11, 1, 0, &ast1700_clk_lock); ++#define SG_LAST_LIST BIT(31) + -+ clks[AST1700_CLK_GATE_UART11CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart11clk-gate"), -+ CREATE_CLK_NAME(id, "uart11clk"), -+ 0, clk_base + AST1700_CLK_STOP2, -+ 6, 0, &ast1700_clk_lock); ++#define SHA_OP_INIT BIT(0) ++#define SHA_OP_UPDATE BIT(1) ++#define SHA_OP_FINAL BIT(2) + -+ //uart12: call bmc uart -+ clks[AST1700_CLK_UART12] = -+ clk_hw_register_mux(NULL, CREATE_CLK_NAME(id, "uart12clk"), -+ (id == 0) ? uartclk_sel0 : uartclk_sel1, -+ (id == 0) ? ARRAY_SIZE(uartclk_sel0) : ARRAY_SIZE(uartclk_sel1), -+ 0, clk_base + AST1700_CLK_SEL1, -+ 12, 1, 0, &ast1700_clk_lock); ++#define ASPEED_HASH_SRC_DMA_BUF_LEN 0xa000 + -+ clks[AST1700_CLK_GATE_UART12CLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "uart12clk-gate"), -+ CREATE_CLK_NAME(id, "uart12clk"), -+ 0, clk_base + AST1700_CLK_STOP2, -+ 7, 0, &ast1700_clk_lock); ++#define ASPEED_RSSS_POLLING_TIME 100 ++#define ASPEED_RSSS_TIMEOUT 100000 /* 100 ms */ + -+ clks[AST1700_CLK_GATE_FSICLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "fsiclk-gate"), NULL, -+ 0, clk_base + AST1700_CLK_STOP2, -+ 8, 0, &ast1700_clk_lock); ++struct aspeed_rsss_dev; + -+ clks[AST1700_CLK_GATE_LTPIPHYCLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "ltpiphyclk-gate"), NULL, -+ CLK_IS_CRITICAL, clk_base + AST1700_CLK_STOP2, -+ 9, 0, &ast1700_clk_lock); ++typedef int (*aspeed_rsss_fn_t)(struct aspeed_rsss_dev *); + -+ clks[AST1700_CLK_GATE_LTPICLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "ltpiclk-gate"), NULL, -+ CLK_IS_CRITICAL, clk_base + AST1700_CLK_STOP2, -+ 10, 0, &ast1700_clk_lock); ++struct aspeed_sg_list { ++ __le64 phy_addr; ++ __le32 len; ++}; + -+ clks[AST1700_CLK_GATE_VGALCLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "vgalclk-gate"), NULL, -+ 0, clk_base + AST1700_CLK_STOP2, -+ 11, 0, &ast1700_clk_lock); ++struct aspeed_engine_rsa { ++ struct tasklet_struct done_task; ++ unsigned long flags; ++ struct akcipher_request *req; + -+ clks[AST1700_CLK_GATE_USBUARTCLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "usbuartclk-gate"), NULL, -+ 0, clk_base + AST1700_CLK_STOP2, -+ 12, 0, &ast1700_clk_lock); ++ /* RSA input/output SRAM buffer */ ++ void __iomem *sram_exp; ++ void __iomem *sram_mod; ++ void __iomem *sram_data; + -+ clk_hw_register_fixed_factor(NULL, CREATE_CLK_NAME(id, "canclk"), CREATE_CLK_NAME(id, "apll"), 0, 1, 10); ++ /* callback func */ ++ aspeed_rsss_fn_t resume; ++}; + -+ clks[AST1700_CLK_GATE_CANCLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "canclk-gate"), -+ CREATE_CLK_NAME(id, "canclk"), -+ 0, clk_base + AST1700_CLK_STOP2, -+ 13, 0, &ast1700_clk_lock); ++struct aspeed_engine_sha3 { ++ struct tasklet_struct done_task; ++ unsigned long flags; ++ struct ahash_request *req; + -+ clks[AST1700_CLK_GATE_PCICLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "pciclk-gate"), NULL, -+ 0, clk_base + AST1700_CLK_STOP2, -+ 14, 0, &ast1700_clk_lock); ++ /* Protects sha3 engine operation enqueue in order */ ++ struct mutex queue_lock; + -+ clks[AST1700_CLK_GATE_SLICLK] = -+ AST1700_clk_hw_register_gate(NULL, CREATE_CLK_NAME(id, "sliclk-gate"), NULL, -+ 0, clk_base + AST1700_CLK_STOP2, -+ 15, 0, &ast1700_clk_lock); ++ /* input buffer for SG */ ++ void *ahash_src_addr; ++ dma_addr_t ahash_src_dma_addr; + -+ of_clk_add_hw_provider(ast1700_node, of_clk_hw_onecell_get, clk_data); ++ /* input buffer for remain */ ++ void *buffer_addr; ++ dma_addr_t buffer_dma_addr; + -+ return 0; -+}; ++ /* output buffer */ ++ void *digest_addr; ++ dma_addr_t digest_dma_addr; + -+CLK_OF_DECLARE_DRIVER(ast1700, "aspeed,ast1700-scu", AST1700_clk_init); ++ dma_addr_t src_dma; ++ size_t src_length; + -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 2026-04-08 18:03:47.794714748 +0000 -@@ -19,7 +19,7 @@ - * This includes the gates (configured from aspeed_g6_gates), plus the - * explicitly-configured clocks (ASPEED_CLK_HPLL and up). - */ --#define ASPEED_G6_NUM_CLKS 73 -+#define ASPEED_G6_NUM_CLKS 76 - - #define ASPEED_G6_SILICON_REV 0x014 - #define CHIP_REVISION_ID GENMASK(23, 16) -@@ -59,8 +59,24 @@ - - #define ASPEED_G6_STRAP1 0x500 - -+#define ASPEED_UARTCLK_FROM_UXCLK 0x338 ++ /* callback func */ ++ aspeed_rsss_fn_t resume; ++ aspeed_rsss_fn_t dma_prepare; + - #define ASPEED_MAC12_CLK_DLY 0x340 -+#define ASPEED_MAC12_CLK_DLY_100M 0x348 -+#define ASPEED_MAC12_CLK_DLY_10M 0x34C ++ unsigned sg_mode:1; ++}; + - #define ASPEED_MAC34_CLK_DLY 0x350 -+#define ASPEED_MAC34_CLK_DLY_100M 0x358 -+#define ASPEED_MAC34_CLK_DLY_10M 0x35C ++struct aspeed_rsss_dev { ++ void __iomem *regs; ++ struct device *dev; ++ int irq; ++ struct clk *clk; ++ struct reset_control *reset_rsa; ++ struct reset_control *reset_sha3; + -+#define ASPEED_G6_MAC34_DRIVING_CTRL 0x458 ++ struct crypto_engine *crypt_engine_rsa; ++ struct crypto_engine *crypt_engine_sha3; + -+#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 @@ - /* AST2600 revision: A0, A1, A2, etc */ - static u8 soc_rev; - -+struct mac_delay_config { -+ u32 tx_delay_1000; -+ u32 rx_delay_1000; -+ u32 tx_delay_100; -+ u32 rx_delay_100; -+ u32 tx_delay_10; -+ u32 rx_delay_10; ++ struct aspeed_engine_rsa rsa_engine; ++ struct aspeed_engine_sha3 sha3_engine; +}; + -+union mac_delay_1g { -+ u32 w; -+ struct { -+ unsigned int tx_delay_1 : 6; /* bit[5:0] */ -+ unsigned int tx_delay_2 : 6; /* bit[11:6] */ -+ unsigned int rx_delay_1 : 6; /* bit[17:12] */ -+ unsigned int rx_delay_2 : 6; /* bit[23:18] */ -+ unsigned int rx_clk_inv_1 : 1; /* bit[24] */ -+ unsigned int rx_clk_inv_2 : 1; /* bit[25] */ -+ unsigned int rmii_tx_data_at_falling_1 : 1; /* bit[26] */ -+ unsigned int rmii_tx_data_at_falling_2 : 1; /* bit[27] */ -+ unsigned int rgmiick_pad_dir : 1; /* bit[28] */ -+ unsigned int rmii_50m_oe_1 : 1; /* bit[29] */ -+ unsigned int rmii_50m_oe_2 : 1; /* bit[30] */ -+ unsigned int rgmii_125m_o_sel : 1; /* bit[31] */ -+ } b; ++enum aspeed_algo_type { ++ ASPEED_ALGO_TYPE_AKCIPHER, ++ ASPEED_ALGO_TYPE_AHASH, +}; + -+union mac_delay_100_10 { -+ u32 w; -+ struct { -+ unsigned int tx_delay_1 : 6; /* bit[5:0] */ -+ unsigned int tx_delay_2 : 6; /* bit[11:6] */ -+ unsigned int rx_delay_1 : 6; /* bit[17:12] */ -+ unsigned int rx_delay_2 : 6; /* bit[23:18] */ -+ unsigned int rx_clk_inv_1 : 1; /* bit[24] */ -+ unsigned int rx_clk_inv_2 : 1; /* bit[25] */ -+ unsigned int reserved_0 : 6; /* bit[31:26] */ -+ } b; ++struct aspeed_rsss_alg { ++ struct aspeed_rsss_dev *rsss_dev; ++ enum aspeed_algo_type type; ++ union { ++ struct akcipher_engine_alg akcipher; ++ struct ahash_engine_alg ahash; ++ } alg; +}; - /* - * 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 @@ - * ref0 and ref1 are essential for the SoC to operate - * mpll is required if SDRAM is used - */ --static const struct aspeed_gate_data aspeed_g6_gates[] = { -+static struct aspeed_gate_data aspeed_g6_gates[] = { - /* clk rst name parent flags */ - [ASPEED_CLK_GATE_MCLK] = { 0, -1, "mclk-gate", "mpll", CLK_IS_CRITICAL }, /* SDRAM */ - [ASPEED_CLK_GATE_ECLK] = { 1, 6, "eclk-gate", "eclk", 0 }, /* Video Engine */ - [ASPEED_CLK_GATE_GCLK] = { 2, 7, "gclk-gate", NULL, 0 }, /* 2D engine */ - /* vclk parent - dclk/d1clk/hclk/mclk */ - [ASPEED_CLK_GATE_VCLK] = { 3, -1, "vclk-gate", NULL, 0 }, /* Video Capture */ -- [ASPEED_CLK_GATE_BCLK] = { 4, 8, "bclk-gate", "bclk", 0 }, /* PCIe/PCI */ -+ [ASPEED_CLK_GATE_BCLK] = { 4, 8, "bclk-gate", "bclk", CLK_IS_CRITICAL }, /* PCIe/PCI */ - /* 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 @@ - /* Reserved 26 */ - [ASPEED_CLK_GATE_EMMCCLK] = { 27, 16, "emmcclk-gate", NULL, 0 }, /* For card clk */ - /* Reserved 28/29/30 */ -- [ASPEED_CLK_GATE_LCLK] = { 32, 32, "lclk-gate", NULL, 0 }, /* LPC */ -- [ASPEED_CLK_GATE_ESPICLK] = { 33, -1, "espiclk-gate", NULL, 0 }, /* eSPI */ -+ [ASPEED_CLK_GATE_LCLK] = { 32, 32, "lclk-gate", NULL, CLK_IS_CRITICAL }, /* LPC */ -+ [ASPEED_CLK_GATE_ESPICLK] = { 33, -1, "espiclk-gate", NULL, CLK_IS_CRITICAL }, /* eSPI */ - [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 @@ - [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 */ -- [ASPEED_CLK_GATE_UART1CLK] = { 48, -1, "uart1clk-gate", "uart", 0 }, /* UART1 */ -- [ASPEED_CLK_GATE_UART2CLK] = { 49, -1, "uart2clk-gate", "uart", 0 }, /* UART2 */ -- [ASPEED_CLK_GATE_UART3CLK] = { 50, -1, "uart3clk-gate", "uart", 0 }, /* UART3 */ -- [ASPEED_CLK_GATE_UART4CLK] = { 51, -1, "uart4clk-gate", "uart", 0 }, /* UART4 */ -+ [ASPEED_CLK_GATE_UART1CLK] = { 48, -1, "uart1clk-gate", "uxclk", CLK_IS_CRITICAL }, /* UART1 */ -+ [ASPEED_CLK_GATE_UART2CLK] = { 49, -1, "uart2clk-gate", "uxclk", CLK_IS_CRITICAL }, /* UART2 */ -+ [ASPEED_CLK_GATE_UART3CLK] = { 50, -1, "uart3clk-gate", "uxclk", 0 }, /* UART3 */ -+ [ASPEED_CLK_GATE_UART4CLK] = { 51, -1, "uart4clk-gate", "uxclk", 0 }, /* UART4 */ - [ASPEED_CLK_GATE_MAC3CLK] = { 52, 52, "mac3clk-gate", "mac34", 0 }, /* MAC3 */ - [ASPEED_CLK_GATE_MAC4CLK] = { 53, 53, "mac4clk-gate", "mac34", 0 }, /* MAC4 */ -- [ASPEED_CLK_GATE_UART6CLK] = { 54, -1, "uart6clk-gate", "uartx", 0 }, /* UART6 */ -- [ASPEED_CLK_GATE_UART7CLK] = { 55, -1, "uart7clk-gate", "uartx", 0 }, /* UART7 */ -- [ASPEED_CLK_GATE_UART8CLK] = { 56, -1, "uart8clk-gate", "uartx", 0 }, /* UART8 */ -- [ASPEED_CLK_GATE_UART9CLK] = { 57, -1, "uart9clk-gate", "uartx", 0 }, /* UART9 */ -- [ASPEED_CLK_GATE_UART10CLK] = { 58, -1, "uart10clk-gate", "uartx", 0 }, /* UART10 */ -- [ASPEED_CLK_GATE_UART11CLK] = { 59, -1, "uart11clk-gate", "uartx", 0 }, /* UART11 */ -- [ASPEED_CLK_GATE_UART12CLK] = { 60, -1, "uart12clk-gate", "uartx", 0 }, /* UART12 */ -- [ASPEED_CLK_GATE_UART13CLK] = { 61, -1, "uart13clk-gate", "uartx", 0 }, /* UART13 */ -+ [ASPEED_CLK_GATE_UART6CLK] = { 54, -1, "uart6clk-gate", "uxclk", 0 }, /* UART6 */ -+ [ASPEED_CLK_GATE_UART7CLK] = { 55, -1, "uart7clk-gate", "uxclk", 0 }, /* UART7 */ -+ [ASPEED_CLK_GATE_UART8CLK] = { 56, -1, "uart8clk-gate", "uxclk", 0 }, /* UART8 */ -+ [ASPEED_CLK_GATE_UART9CLK] = { 57, -1, "uart9clk-gate", "uxclk", 0 }, /* UART9 */ -+ [ASPEED_CLK_GATE_UART10CLK] = { 58, -1, "uart10clk-gate", "uxclk", 0 }, /* UART10 */ -+ [ASPEED_CLK_GATE_UART11CLK] = { 59, -1, "uart11clk-gate", "uxclk", CLK_IS_CRITICAL }, /* UART11 */ -+ [ASPEED_CLK_GATE_UART12CLK] = { 60, -1, "uart12clk-gate", "uxclk", 0 }, /* UART12 */ -+ [ASPEED_CLK_GATE_UART13CLK] = { 61, -1, "uart13clk-gate", "uxclk", 0 }, /* UART13 */ - [ASPEED_CLK_GATE_FSICLK] = { 62, 59, "fsiclk-gate", "fsiclk", 0 }, /* FSI */ ++ ++/* RSA related */ ++struct aspeed_rsa_ctx { ++ struct aspeed_rsss_dev *rsss_dev; ++ ++ struct rsa_key key; ++ int enc; ++ u8 *n; ++ u8 *e; ++ u8 *d; ++ size_t n_sz; ++ size_t e_sz; ++ size_t d_sz; ++ ++ aspeed_rsss_fn_t trigger; ++ ++ struct crypto_akcipher *fallback_tfm; ++}; ++ ++enum aspeed_rsa_key_mode { ++ ASPEED_RSA_EXP_MODE = 0, ++ ASPEED_RSA_MOD_MODE, ++ ASPEED_RSA_DATA_MODE, ++}; ++ ++/* Hash related */ ++struct aspeed_sha3_ctx { ++ struct aspeed_rsss_dev *rsss_dev; ++}; ++ ++struct aspeed_sha3_reqctx { ++ unsigned long flags; /* final update flag should no use */ ++ unsigned long op; /* final or update */ ++ u32 cmd; /* trigger cmd */ ++ ++ /* walk state */ ++ struct scatterlist *src_sg; ++ int src_nents; ++ unsigned int offset; /* offset in current sg */ ++ unsigned int total; /* per update length */ ++ ++ size_t digsize; ++ size_t blksize; ++ ++ /* remain data buffer */ ++ u8 buffer[SHA3_512_BLOCK_SIZE * 2]; ++ size_t bufcnt; /* buffer counter */ ++ ++ /* output buffer */ ++ u8 digest[SHA3_512_DIGEST_SIZE]; ++ u64 digcnt[2]; ++}; ++ ++/******************************************************************************/ ++ ++#define ast_rsss_write(rsss, val, offset) \ ++ writel((val), (rsss)->regs + (offset)) ++ ++#define ast_rsss_read(rsss, offset) \ ++ readl((rsss)->regs + (offset)) ++ ++int aspeed_rsss_rsa_init(struct aspeed_rsss_dev *rsss_dev); ++void aspeed_rsss_rsa_exit(struct aspeed_rsss_dev *rsss_dev); ++int aspeed_rsss_sha3_init(struct aspeed_rsss_dev *rsss_dev); ++void aspeed_rsss_sha3_exit(struct aspeed_rsss_dev *rsss_dev); ++ ++extern struct aspeed_rsss_alg aspeed_rsss_algs_rsa; ++extern struct aspeed_rsss_alg aspeed_rsss_algs_sha3_224; ++extern struct aspeed_rsss_alg aspeed_rsss_algs_sha3_256; ++extern struct aspeed_rsss_alg aspeed_rsss_algs_sha3_384; ++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 }; -@@ -184,6 +239,18 @@ - { 0 } +@@ -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 }; -+static const struct clk_div_table ast2600_sd_div_table[] = { -+ { 0x0, 2 }, -+ { 0x1, 4 }, -+ { 0x2, 6 }, -+ { 0x3, 8 }, -+ { 0x4, 10 }, -+ { 0x5, 12 }, -+ { 0x6, 14 }, -+ { 0x7, 1 }, -+ { 0 } -+}; +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); + - static const struct clk_div_table ast2600_mac_div_table[] = { - { 0x0, 4 }, - { 0x1, 4 }, -@@ -384,9 +451,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; -+ u32 val; -+ int ret; ++ 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; - /* Use set to clear register */ -- return regmap_write(ar->map, reg + 0x04, rst); -+ ret = regmap_write(ar->map, reg + 0x04, rst); -+ /* Add dummy read to ensure the write transfer is finished */ -+ regmap_read(ar->map, reg + 4, &val); -+ return ret; - } ++ if (i10nm_channel_disabled(imc, i)) { ++ edac_dbg(1, "mc%d ch%d is disabled.\n", imc->mc, i); ++ continue; ++ } ++ + ndimms = 0; - static int aspeed_g6_reset_assert(struct reset_controller_dev *rcdev, -@@ -458,11 +530,6 @@ - return hw; + if (res_cfg->type != GNR) +diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c +--- a/drivers/edac/synopsys_edac.c 2025-08-01 08:48:47.000000000 +0000 ++++ b/drivers/edac/synopsys_edac.c 2025-12-23 10:16:21.155032150 +0000 +@@ -332,20 +332,26 @@ + #endif + }; + ++enum synps_platform_type { ++ ZYNQ, ++ ZYNQMP, ++ SYNPS, ++}; ++ + /** + * struct synps_platform_data - synps platform data structure. ++ * @platform: Identifies the target hardware platform + * @get_error_info: Get EDAC error info. + * @get_mtype: Get mtype. + * @get_dtype: Get dtype. +- * @get_ecc_state: Get ECC state. + * @get_mem_info: Get EDAC memory info + * @quirks: To differentiate IPs. + */ + struct synps_platform_data { ++ enum synps_platform_type platform; + int (*get_error_info)(struct synps_edac_priv *priv); + enum mem_type (*get_mtype)(const void __iomem *base); + enum dev_type (*get_dtype)(const void __iomem *base); +- bool (*get_ecc_state)(void __iomem *base); + #ifdef CONFIG_EDAC_DEBUG + u64 (*get_mem_info)(struct synps_edac_priv *priv); + #endif +@@ -720,51 +726,38 @@ + return dt; } --static const char *const emmc_extclk_parent_names[] = { -- "emmc_extclk_hpll_in", -- "mpll", --}; +-/** +- * zynq_get_ecc_state - Return the controller ECC enable/disable status. +- * @base: DDR memory controller base address. +- * +- * Get the ECC enable/disable status of the controller. +- * +- * Return: true if enabled, otherwise false. +- */ +-static bool zynq_get_ecc_state(void __iomem *base) +-{ +- enum dev_type dt; +- u32 ecctype; - - static const char * const vclk_parent_names[] = { - "dpll", - "d1pll", -@@ -484,7 +551,7 @@ - struct aspeed_reset *ar; - struct regmap *map; - struct clk_hw *hw; -- u32 val, rate; -+ u32 val; - int i, ret; - - map = syscon_node_to_regmap(dev->of_node); -@@ -510,70 +577,50 @@ - return ret; - } - -- /* UART clock div13 setting */ -- regmap_read(map, ASPEED_G6_MISC_CTRL, &val); -- if (val & UART_DIV13_EN) -- rate = 24000000 / 13; -- else -- rate = 24000000; -- hw = clk_hw_register_fixed_rate(dev, "uart", NULL, 0, rate); -- if (IS_ERR(hw)) -- return PTR_ERR(hw); -- aspeed_g6_clk_data->hws[ASPEED_CLK_UART] = hw; +- dt = zynq_get_dtype(base); +- if (dt == DEV_UNKNOWN) +- return false; - -- /* UART6~13 clock div13 setting */ -- regmap_read(map, 0x80, &val); -- if (val & BIT(31)) -- rate = 24000000 / 13; -- else -- rate = 24000000; -- hw = clk_hw_register_fixed_rate(dev, "uartx", NULL, 0, rate); -- if (IS_ERR(hw)) -- return PTR_ERR(hw); -- aspeed_g6_clk_data->hws[ASPEED_CLK_UARTX] = hw; +- ecctype = readl(base + SCRUB_OFST) & SCRUB_MODE_MASK; +- if ((ecctype == SCRUB_MODE_SECDED) && (dt == DEV_X2)) +- return true; - -- /* 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); +- return false; +-} - -- hw = clk_hw_register_mux(dev, "emmc_extclk_mux", -- emmc_extclk_parent_names, -- ARRAY_SIZE(emmc_extclk_parent_names), 0, -- scu_g6_base + ASPEED_G6_CLK_SELECTION1, 11, 1, -- 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); - -- hw = clk_hw_register_divider_table(dev, "emmc_extclk", -- "emmc_extclk_gate", 0, -- scu_g6_base + -- ASPEED_G6_CLK_SELECTION1, 12, -- 3, 0, ast2600_emmc_extclk_div_table, -+ //ast2600 emmc clk should under 200Mhz -+ hw = clk_hw_register_divider_table(dev, "emmc_extclk", "emmc_extclk_gate", 0, -+ scu_g6_base + ASPEED_G6_CLK_SELECTION1, 12, 3, 0, -+ ast2600_emmc_extclk_div_table, - &aspeed_g6_clk_lock); - if (IS_ERR(hw)) - return PTR_ERR(hw); - aspeed_g6_clk_data->hws[ASPEED_CLK_EMMC] = hw; +-/** +- * zynqmp_get_ecc_state - Return the controller ECC enable/disable status. +- * @base: DDR memory controller base address. +- * +- * Get the ECC enable/disable status for the controller. +- * +- * Return: a ECC status boolean i.e true/false - enabled/disabled. +- */ +-static bool zynqmp_get_ecc_state(void __iomem *base) ++static bool get_ecc_state(struct synps_edac_priv *priv) + { ++ u32 ecctype, clearval; + enum dev_type dt; +- u32 ecctype; -- /* SD/SDIO clock divider and gate */ -- hw = clk_hw_register_gate(dev, "sd_extclk_gate", "hpll", 0, -- scu_g6_base + ASPEED_G6_CLK_SELECTION4, 31, 0, -- &aspeed_g6_clk_lock); -- if (IS_ERR(hw)) -- return PTR_ERR(hw); -+ clk_hw_register_fixed_rate(NULL, "hclk", NULL, 0, 200000000); +- dt = zynqmp_get_dtype(base); +- if (dt == DEV_UNKNOWN) +- return false; +- +- ecctype = readl(base + ECC_CFG0_OFST) & SCRUB_MODE_MASK; +- if ((ecctype == SCRUB_MODE_SECDED) && +- ((dt == DEV_X2) || (dt == DEV_X4) || (dt == DEV_X8))) +- return true; ++ if (priv->p_data->platform == ZYNQ) { ++ dt = zynq_get_dtype(priv->baseaddr); ++ if (dt == DEV_UNKNOWN) ++ return false; + -+ regmap_read(map, 0x310, &val); -+ if (val & BIT(8)) { -+ /* SD/SDIO clock divider and gate */ -+ hw = clk_hw_register_gate(dev, "sd_extclk_gate", "apll", 0, -+ scu_g6_base + ASPEED_G6_CLK_SELECTION4, 31, 0, -+ &aspeed_g6_clk_lock); -+ if (IS_ERR(hw)) -+ return PTR_ERR(hw); ++ ecctype = readl(priv->baseaddr + SCRUB_OFST) & SCRUB_MODE_MASK; ++ if (ecctype == SCRUB_MODE_SECDED && dt == DEV_X2) { ++ clearval = ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_UE_ERR; ++ writel(clearval, priv->baseaddr + ECC_CTRL_OFST); ++ writel(0x0, priv->baseaddr + ECC_CTRL_OFST); ++ return true; ++ } + } else { -+ /* SD/SDIO clock divider and gate */ -+ hw = clk_hw_register_gate(dev, "sd_extclk_gate", "hclk", 0, -+ scu_g6_base + ASPEED_G6_CLK_SELECTION4, 31, 0, -+ &aspeed_g6_clk_lock); -+ if (IS_ERR(hw)) -+ return PTR_ERR(hw); -+ } -+ - hw = clk_hw_register_divider_table(dev, "sd_extclk", "sd_extclk_gate", -- 0, scu_g6_base + ASPEED_G6_CLK_SELECTION4, 28, 3, 0, -- ast2600_div_table, -- &aspeed_g6_clk_lock); -+ 0, scu_g6_base + ASPEED_G6_CLK_SELECTION4, 28, 3, 0, -+ ast2600_sd_div_table, -+ &aspeed_g6_clk_lock); - if (IS_ERR(hw)) - return PTR_ERR(hw); ++ dt = zynqmp_get_dtype(priv->baseaddr); ++ if (dt == DEV_UNKNOWN) ++ return false; + - aspeed_g6_clk_data->hws[ASPEED_CLK_SDIO] = hw; ++ ecctype = readl(priv->baseaddr + ECC_CFG0_OFST) & SCRUB_MODE_MASK; ++ if (ecctype == SCRUB_MODE_SECDED && ++ (dt == DEV_X2 || dt == DEV_X4 || dt == DEV_X8)) { ++ clearval = readl(priv->baseaddr + ECC_CLR_OFST) | ++ ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_CE_ERRCNT | ++ ECC_CTRL_CLR_UE_ERR | ECC_CTRL_CLR_UE_ERRCNT; ++ writel(clearval, priv->baseaddr + ECC_CLR_OFST); ++ return true; ++ } ++ } - /* MAC1/2 RMII 50MHz RCLK */ -@@ -645,8 +692,8 @@ - return PTR_ERR(hw); - aspeed_g6_clk_data->hws[ASPEED_CLK_LHCLK] = hw; + return false; + } +@@ -934,18 +927,18 @@ + } -- /* gfx d1clk : use dp clk */ -- regmap_update_bits(map, ASPEED_G6_CLK_SELECTION1, GENMASK(10, 8), BIT(10)); -+ /* gfx d1clk : use usb phy */ -+ regmap_update_bits(map, ASPEED_G6_CLK_SELECTION1, GENMASK(10, 8), BIT(9)); - /* SoC Display clock selection */ - hw = clk_hw_register_mux(dev, "d1clk", d1clk_parent_names, - ARRAY_SIZE(d1clk_parent_names), 0, -@@ -677,6 +724,8 @@ - return PTR_ERR(hw); - aspeed_g6_clk_data->hws[ASPEED_CLK_VCLK] = hw; + static const struct synps_platform_data zynq_edac_def = { ++ .platform = ZYNQ, + .get_error_info = zynq_get_error_info, + .get_mtype = zynq_get_mtype, + .get_dtype = zynq_get_dtype, +- .get_ecc_state = zynq_get_ecc_state, + .quirks = 0, + }; -+ //vclk : force disable dynmamic slow down and fix vclk = eclk / 2 -+ regmap_update_bits(map, ASPEED_G6_CLK_SELECTION1, GENMASK(31, 28), 0); - /* 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 @@ - return PTR_ERR(hw); - aspeed_g6_clk_data->hws[ASPEED_CLK_ECLK] = hw; + static const struct synps_platform_data zynqmp_edac_def = { ++ .platform = ZYNQMP, + .get_error_info = zynqmp_get_error_info, + .get_mtype = zynqmp_get_mtype, + .get_dtype = zynqmp_get_dtype, +- .get_ecc_state = zynqmp_get_ecc_state, + #ifdef CONFIG_EDAC_DEBUG + .get_mem_info = zynqmp_get_mem_info, + #endif +@@ -957,10 +950,10 @@ + }; -+ /* uartx parent assign*/ -+ for (i = 0; i < 13; i++) { -+ if (i < 6 && i != 4) { -+ regmap_read(map, 0x310, &val); -+ if (val & BIT(i)) -+ aspeed_g6_gates[ASPEED_CLK_GATE_UART1CLK + i].parent_name = "huxclk"; -+ else -+ aspeed_g6_gates[ASPEED_CLK_GATE_UART1CLK + i].parent_name = "uxclk"; -+ } -+ if (i == 4) -+ aspeed_g6_gates[ASPEED_CLK_GATE_UART1CLK + i].parent_name = "uart5"; -+ if (i > 5 && i != 4) { -+ regmap_read(map, 0x314, &val); -+ if (val & BIT(i)) -+ aspeed_g6_gates[ASPEED_CLK_GATE_UART1CLK + i].parent_name = "huxclk"; -+ else -+ aspeed_g6_gates[ASPEED_CLK_GATE_UART1CLK + i].parent_name = "uxclk"; -+ } + static const struct synps_platform_data synopsys_edac_def = { ++ .platform = SYNPS, + .get_error_info = zynqmp_get_error_info, + .get_mtype = zynqmp_get_mtype, + .get_dtype = zynqmp_get_dtype, +- .get_ecc_state = zynqmp_get_ecc_state, + .quirks = (DDR_ECC_INTR_SUPPORT | DDR_ECC_INTR_SELF_CLEAR + #ifdef CONFIG_EDAC_DEBUG + | DDR_ECC_DATA_POISON_SUPPORT +@@ -1390,10 +1383,6 @@ + if (!p_data) + return -ENODEV; + +- if (!p_data->get_ecc_state(baseaddr)) { +- edac_printk(KERN_INFO, EDAC_MC, "ECC not enabled\n"); +- return -ENXIO; +- } + + layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; + layers[0].size = SYNPS_EDAC_NR_CSROWS; +@@ -1413,6 +1402,12 @@ + priv = mci->pvt_info; + priv->baseaddr = baseaddr; + priv->p_data = p_data; ++ if (!get_ecc_state(priv)) { ++ edac_printk(KERN_INFO, EDAC_MC, "ECC not enabled\n"); ++ rc = -ENODEV; ++ goto free_edac_mc; + } + - 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 @@ - static void __init aspeed_g6_cc(struct regmap *map) - { - struct clk_hw *hw; -- u32 val, div, divbits, axi_div, ahb_div; -+ u32 val, freq, div, divbits, axi_div, ahb_div; -+ u32 mult; + spin_lock_init(&priv->reglock); - clk_hw_register_fixed_rate(NULL, "clkin", NULL, 0, 25000000); + mc_init(mci, pdev); +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 -@@ -814,6 +884,55 @@ - hw = clk_hw_register_fixed_rate(NULL, "usb-phy-40m", NULL, 0, 40000000); - aspeed_g6_clk_data->hws[ASPEED_CLK_USBPHY_40M] = hw; + #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; + }; -+ /* uart5 clock selection */ -+ regmap_read(map, ASPEED_G6_MISC_CTRL, &val); -+ if (val & UART_DIV13_EN) -+ div = 13; -+ else -+ div = 1; -+ regmap_read(map, ASPEED_G6_CLK_SELECTION2, &val); -+ if (val & BIT(14)) -+ freq = 192000000; -+ else -+ freq = 24000000; -+ freq = freq / div; -+ -+ aspeed_g6_clk_data->hws[ASPEED_CLK_UART5] = clk_hw_register_fixed_rate(NULL, "uart5", NULL, 0, freq); -+ -+ /* UART1~13 clock div13 setting except uart5 */ -+ regmap_read(map, ASPEED_G6_CLK_SELECTION5, &val); -+ -+ switch (val & 0x3) { -+ case 0: -+ aspeed_g6_clk_data->hws[ASPEED_CLK_UARTX] = clk_hw_register_fixed_factor(NULL, "uartx", "apll", 0, 1, 4); -+ break; -+ case 1: -+ aspeed_g6_clk_data->hws[ASPEED_CLK_UARTX] = clk_hw_register_fixed_factor(NULL, "uartx", "apll", 0, 1, 2); -+ break; -+ case 2: -+ aspeed_g6_clk_data->hws[ASPEED_CLK_UARTX] = clk_hw_register_fixed_factor(NULL, "uartx", "apll", 0, 1, 1); -+ break; -+ case 3: -+ aspeed_g6_clk_data->hws[ASPEED_CLK_UARTX] = clk_hw_register_fixed_factor(NULL, "uartx", "ahb", 0, 1, 1); -+ break; -+ } -+ -+ /* uxclk */ -+ regmap_read(map, ASPEED_UARTCLK_FROM_UXCLK, &val); -+ div = ((val >> 8) & 0x3ff) * 2; -+ mult = val & 0xff; -+ -+ hw = clk_hw_register_fixed_factor(NULL, "uxclk", "uartx", 0, mult, div); -+ aspeed_g6_clk_data->hws[ASPEED_CLK_UXCLK] = hw; -+ -+ /* huxclk */ -+ regmap_read(map, 0x33c, &val); -+ div = ((val >> 8) & 0x3ff) * 2; -+ mult = val & 0xff; -+ -+ hw = clk_hw_register_fixed_factor(NULL, "huxclk", "uartx", 0, mult, div); -+ aspeed_g6_clk_data->hws[ASPEED_CLK_HUXCLK] = hw; ++struct aspeed_fsi_match_data { ++ bool sup_ahb_access; ++}; + - /* 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 @@ - 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; + #define to_fsi_master_aspeed(m) \ + container_of(m, struct fsi_master_aspeed, master) -@@ -863,6 +986,100 @@ - return; +@@ -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; } -+ of_property_read_u32(np, "uart-clk-source", &uart_clk_source); -+ -+ if (uart_clk_source) { -+ if (uart_clk_source & GENMASK(5, 0)) -+ regmap_update_bits(map, ASPEED_G6_CLK_SELECTION4, GENMASK(5, 0), uart_clk_source & GENMASK(5, 0)); -+ -+ if (uart_clk_source & GENMASK(12, 6)) -+ regmap_update_bits(map, ASPEED_G6_CLK_SELECTION5, GENMASK(12, 6), uart_clk_source & GENMASK(12, 6)); -+ } -+ -+ /* fixed settings for RGMII/RMII clock generator */ -+ /* MAC1/2 RGMII 125MHz = EPLL / 8 */ -+ regmap_update_bits(map, ASPEED_G6_CLK_SELECTION2, GENMASK(23, 20), -+ (0x7 << 20)); -+ -+ /* MAC3/4 RMII 50MHz = HCLK / 4 */ -+ regmap_update_bits(map, ASPEED_G6_CLK_SELECTION4, GENMASK(18, 16), -+ (0x3 << 16)); ++ 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); + -+ /* 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); + 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, ++}; + -+ 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); ++static const struct aspeed_fsi_match_data ast2700_match_data = { ++ .sup_ahb_access = 1, ++}; + -+ /* 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)); + 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. + - aspeed_g6_cc(map); - ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, aspeed_g6_clk_data); - 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 2026-04-08 18:03:47.777715058 +0000 -@@ -0,0 +1,1244 @@ + 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 +/* -+ * Copyright (c) 2024 ASPEED Technology Inc. -+ * Author: Ryan Chen ++ * Copyright (c) 2024 ASPEED ++ * ++ * Author: Billy Tsai + */ -+#include ++ ++#include ++#include ++#include ++#include ++#include +#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) + -+#define REVISION_ID GENMASK(23, 16) ++static inline u32 field_get(u32 _mask, u32 _val) ++{ ++ return (((_val) & (_mask)) >> (ffs(_mask) - 1)); ++} + -+/* SOC0 */ -+#define SCU0_HWSTRAP1 0x010 -+#define SCU0_CLK_STOP 0x240 -+#define SCU0_CLK_SEL1 0x280 -+#define SCU0_CLK_SEL2 0x284 -+#define GET_USB_REFCLK_DIV(x) ((GENMASK(23, 20) & (x)) >> 20) -+#define UART_DIV13_EN BIT(30) -+#define SCU0_HPLL_PARAM 0x300 -+#define SCU0_DPLL_PARAM 0x308 -+#define SCU0_MPLL_PARAM 0x310 -+#define SCU0_D0CLK_PARAM 0x320 -+#define SCU0_D1CLK_PARAM 0x330 -+#define SCU0_CRT0CLK_PARAM 0x340 -+#define SCU0_CRT1CLK_PARAM 0x350 -+#define SCU0_MPHYCLK_PARAM 0x360 ++static inline u32 field_prep(u32 _mask, u32 _val) ++{ ++ return (((_val) << (ffs(_mask) - 1)) & (_mask)); ++} + -+/* SOC1 */ -+#define SCU1_CLK_STOP 0x240 -+#define AST2755_SCU1_CLK_STOP 0x248 -+#define SCU1_CLK_STOP2 0x260 -+#define SCU1_CLK_SEL1 0x280 -+#define SCU1_CLK_SEL2 0x284 -+#define SCU1_CLK_I3C_DIV_MASK GENMASK(25, 23) -+#define SCU1_CLK_I3C_DIV(n) ((n) - 1) -+#define UXCLK_MASK GENMASK(1, 0) -+#define HUXCLK_MASK GENMASK(4, 3) -+#define SCU1_HPLL_PARAM 0x300 -+#define SCU1_APLL_PARAM 0x310 -+#define SCU1_DPLL_PARAM 0x320 -+#define SCU1_UXCLK_CTRL 0x330 -+#define SCU1_HUXCLK_CTRL 0x334 -+#define SCU1_MAC12_CLK_DLY 0x390 ++static inline void ast_write_bits(void __iomem *addr, u32 mask, u32 val) ++{ ++ iowrite32((ioread32(addr) & ~(mask)) | field_prep(mask, val), addr); ++} + -+struct mac_delay_config { -+ u32 tx_delay_1000; -+ u32 rx_delay_1000; -+ u32 tx_delay_100; -+ u32 rx_delay_100; -+ u32 tx_delay_10; -+ u32 rx_delay_10; -+}; ++static inline void ast_clr_bits(void __iomem *addr, u32 mask) ++{ ++ iowrite32((ioread32(addr) & ~(mask)), addr); ++} + -+enum ast2700_clk_type { -+ CLK_MUX, -+ CLK_PLL, -+ CLK_HPLL, -+ CLK_GATE, -+ CLK_MISC, -+ CLK_FIXED, -+ CLK_FIXED_DISPLAY, -+ CLK_DIVIDER, -+ CLK_UART_PLL, -+ CLK_FIXED_FACTOR, -+ CLK_GATE_ASPEED, ++struct aspeed_ltpi_gpio { ++ struct gpio_chip chip; ++ struct device *dev; ++ raw_spinlock_t lock; ++ void __iomem *base; ++ int irq; +}; + -+struct ast2700_clk_fixed_factor_data { -+ unsigned int mult; -+ unsigned int div; -+ int parent_id; -+}; ++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; ++} + -+struct ast2700_clk_gate_data { -+ int parent_id; -+ u32 flags; -+ u32 reg; -+ u8 bit; -+}; ++static void aspeed_ltpi_gpio_irq_init_valid_mask(struct gpio_chip *gc, ++ unsigned long *valid_mask, ++ unsigned int ngpios) ++{ ++ unsigned int i; + -+struct ast2700_clk_mux_data { -+ const struct clk_hw **parent_hws; -+ const unsigned int *parent_ids; -+ unsigned int num_parents; -+ u8 bit_shift; -+ u8 bit_width; -+ u32 reg; -+}; ++ /* input GPIOs are even bits */ ++ for (i = 0; i < ngpios; i++) { ++ if (i % 2) ++ clear_bit(i, valid_mask); ++ } ++} + -+struct ast2700_clk_div_data { -+ const struct clk_div_table *div_table; -+ unsigned int parent_id; -+ u8 bit_shift; -+ u8 bit_width; -+ u32 reg; -+}; ++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; + -+struct ast2700_clk_pll_data { -+ unsigned int parent_id; -+ u32 reg; -+}; ++ raw_spin_lock_irqsave(&gpio->lock, flags); + -+struct ast2700_clk_fixed_rate_data { -+ unsigned long fixed_rate; -+}; ++ 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); ++ } + -+struct ast2700_clk_display_fixed_data { -+ u32 reg; -+}; ++ raw_spin_unlock_irqrestore(&gpio->lock, flags); + -+struct ast2700_clk_info { -+ u32 id; -+ const char *name; -+ u32 reg; -+ u32 type; -+ union { -+ struct ast2700_clk_fixed_factor_data factor; -+ struct ast2700_clk_fixed_rate_data rate; -+ struct ast2700_clk_display_fixed_data display_rate; -+ struct ast2700_clk_gate_data gate; -+ struct ast2700_clk_div_data div; -+ struct ast2700_clk_pll_data pll; -+ struct ast2700_clk_mux_data mux; -+ } data; -+}; ++ return 0; ++} + -+struct ast2700_clk_data { -+ const struct ast2700_clk_info *clk_info; -+ unsigned int nr_clks; -+ const int scu; -+}; ++static bool aspeed_ltpi_gpio_is_input(unsigned int offset) ++{ ++ return !(offset % 2); ++} + -+struct ast2700_clk_ctrl { -+ const struct ast2700_clk_data *clk_data; -+ struct device *dev; -+ void __iomem *base; -+ spinlock_t lock; /* clk lock */ -+}; ++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; + -+static const struct clk_div_table ast2700_rgmii_div_table[] = { -+ { 0x0, 4 }, -+ { 0x1, 4 }, -+ { 0x2, 6 }, -+ { 0x3, 8 }, -+ { 0x4, 10 }, -+ { 0x5, 12 }, -+ { 0x6, 14 }, -+ { 0x7, 16 }, -+ { 0 } -+}; ++ raw_spin_lock_irqsave(&gpio->lock, flags); + -+static const struct clk_div_table ast2700_rmii_div_table[] = { -+ { 0x0, 8 }, -+ { 0x1, 8 }, -+ { 0x2, 12 }, -+ { 0x3, 16 }, -+ { 0x4, 20 }, -+ { 0x5, 24 }, -+ { 0x6, 28 }, -+ { 0x7, 32 }, -+ { 0 } -+}; ++ mask = aspeed_ltpi_gpio_is_input(offset) ? LTPI_GPIO_IN_DATA : ++ LTPI_GPIO_OUT_DATA; ++ rc = !!(field_get(mask, ioread32(addr))); + -+static const struct clk_div_table ast2700_clk_div_table[] = { -+ { 0x0, 2 }, -+ { 0x1, 2 }, -+ { 0x2, 3 }, -+ { 0x3, 4 }, -+ { 0x4, 5 }, -+ { 0x5, 6 }, -+ { 0x6, 7 }, -+ { 0x7, 8 }, -+ { 0 } -+}; ++ raw_spin_unlock_irqrestore(&gpio->lock, flags); + -+static const struct clk_div_table ast2700_clk_div_table2[] = { -+ { 0x0, 2 }, -+ { 0x1, 4 }, -+ { 0x2, 6 }, -+ { 0x3, 8 }, -+ { 0x4, 10 }, -+ { 0x5, 12 }, -+ { 0x6, 14 }, -+ { 0x7, 16 }, -+ { 0 } -+}; ++ return rc; ++} + -+static const struct clk_div_table ast2700_hclk_div_table[] = { -+ { 0x0, 6 }, -+ { 0x1, 5 }, -+ { 0x2, 4 }, -+ { 0x3, 7 }, -+ { 0 } -+}; ++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; + -+static const struct clk_div_table ast2700_clk_uart_div_table[] = { -+ { 0x0, 1 }, -+ { 0x1, 13 }, -+ { 0 } -+}; ++ if (aspeed_ltpi_gpio_is_input(offset)) ++ return -EINVAL; + -+/* soc 0 */ -+static const unsigned int psp_parent_ids[] = { -+ SCU0_CLK_MPLL, -+ SCU0_CLK_HPLL, -+ SCU0_CLK_HPLL, -+ SCU0_CLK_HPLL, -+ SCU0_CLK_MPLL_DIV2, -+ SCU0_CLK_HPLL_DIV2, -+ SCU0_CLK_HPLL, -+ SCU0_CLK_HPLL -+}; ++ reg = ioread32(addr); + -+static const struct clk_hw *psp_parent_hws[ARRAY_SIZE(psp_parent_ids)]; ++ if (val) ++ reg |= LTPI_GPIO_OUT_DATA; ++ else ++ reg &= ~LTPI_GPIO_OUT_DATA; + -+static const unsigned int hclk_parent_ids[] = { -+ SCU0_CLK_HPLL, -+ SCU0_CLK_MPLL -+}; ++ iowrite32(reg, addr); + -+static const struct clk_hw *hclk_parent_hws[ARRAY_SIZE(hclk_parent_ids)]; ++ return 0; ++} + -+static const unsigned int emmc_parent_ids[] = { -+ SCU0_CLK_MPLL_DIV4, -+ SCU0_CLK_HPLL_DIV4 -+}; ++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; + -+static const struct clk_hw *emmc_parent_hws[ARRAY_SIZE(emmc_parent_ids)]; ++ raw_spin_lock_irqsave(&gpio->lock, flags); ++ ltpi_gpio_set_value(gc, offset, val); ++ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++} + -+static const unsigned int mphy_parent_ids[] = { -+ SCU0_CLK_MPLL, -+ SCU0_CLK_HPLL, -+ SCU0_CLK_DPLL, -+ SCU0_CLK_192M -+}; ++static int aspeed_ltpi_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) ++{ ++ return aspeed_ltpi_gpio_is_input(offset) ? 0 : -EINVAL; ++} + -+static const struct clk_hw *mphy_parent_hws[ARRAY_SIZE(mphy_parent_ids)]; ++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; + -+static const unsigned int u2phy_parent_ids[] = { -+ SCU0_CLK_MPLL, -+ SCU0_CLK_HPLL -+}; ++ raw_spin_lock_irqsave(&gpio->lock, flags); ++ rc = ltpi_gpio_set_value(gc, offset, val); ++ raw_spin_unlock_irqrestore(&gpio->lock, flags); + -+static const struct clk_hw *u2phy_parent_hws[ARRAY_SIZE(u2phy_parent_ids)]; ++ return rc; ++} + -+static const unsigned int uart_parent_ids[] = { -+ SCU0_CLK_24M, -+ SCU0_CLK_192M -+}; ++static int aspeed_ltpi_gpio_get_direction(struct gpio_chip *gc, ++ unsigned int offset) ++{ ++ return !!aspeed_ltpi_gpio_is_input(offset); ++} + -+static const struct clk_hw *uart_parent_hws[ARRAY_SIZE(uart_parent_ids)]; ++static void irqd_to_aspeed_ltpi_gpio_data(struct irq_data *d, ++ struct aspeed_ltpi_gpio **gpio, ++ int *offset) ++{ ++ struct aspeed_ltpi_gpio *internal; + -+/* soc 1 */ -+static const unsigned int uartx_parent_ids[] = { -+ SCU1_CLK_UARTX, -+ SCU1_CLK_HUARTX -+}; ++ *offset = irqd_to_hwirq(d); ++ internal = irq_data_get_irq_chip_data(d); ++ WARN_ON(!internal); + -+static const struct clk_hw *uartx_parent_hws[ARRAY_SIZE(uartx_parent_ids)]; ++ *gpio = internal; ++} + -+static const unsigned int uxclk_parent_ids[] = { -+ SCU1_CLK_APLL_DIV4, -+ SCU1_CLK_APLL_DIV2, -+ SCU1_CLK_APLL, -+ SCU1_CLK_HPLL -+}; ++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; + -+static const struct clk_hw *uxclk_parent_hws[ARRAY_SIZE(uxclk_parent_ids)]; ++ irqd_to_aspeed_ltpi_gpio_data(d, &gpio, &offset); + -+static const unsigned int sdclk_parent_ids[] = { -+ SCU1_CLK_HPLL, -+ SCU1_CLK_APLL -+}; ++ status_addr = gpio->base + LTPI_GPIO_CTRL_REG_OFFSET(offset >> 1); + -+static const struct clk_hw *sdclk_parent_hws[ARRAY_SIZE(sdclk_parent_ids)]; ++ raw_spin_lock_irqsave(&gpio->lock, flags); + -+#define FIXED_CLK(_id, _name, _rate) \ -+ { \ -+ .id = _id, \ -+ .type = CLK_FIXED, \ -+ .name = _name, \ -+ .data = { .rate = { .fixed_rate = _rate, } }, \ -+ } ++ ast_write_bits(status_addr, LTPI_GPIO_IRQ_STS, 1); + -+#define FIXED_DISPLAY_CLK(_id, _name, _reg) \ -+ { \ -+ .id = _id, \ -+ .type = CLK_FIXED_DISPLAY, \ -+ .name = _name, \ -+ .data = { .display_rate = { .reg = _reg } }, \ -+ } ++ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++} + -+#define PLL_CLK(_id, _type, _name, _parent_id, _reg) \ -+ { \ -+ .id = _id, \ -+ .type = _type, \ -+ .name = _name, \ -+ .data = { .pll = { \ -+ .parent_id = _parent_id, \ -+ .reg = _reg, \ -+ } }, \ -+ } ++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; + -+#define MUX_CLK(_id, _name, _parent_ids, _num_parents, _parent_hws, _reg, _shift, _width) \ -+ { \ -+ .id = _id, \ -+ .type = CLK_MUX, \ -+ .name = _name, \ -+ .data = { \ -+ .mux = { \ -+ .parent_ids = _parent_ids, \ -+ .parent_hws = _parent_hws, \ -+ .num_parents = _num_parents, \ -+ .reg = (_reg), \ -+ .bit_shift = _shift, \ -+ .bit_width = _width, \ -+ }, \ -+ }, \ -+ } ++ irqd_to_aspeed_ltpi_gpio_data(d, &gpio, &offset); ++ addr = gpio->base + LTPI_GPIO_CTRL_REG_OFFSET(offset >> 1); + -+#define DIVIDER_CLK(_id, _name, _parent_id, _reg, _shift, _width, _div_table) \ -+ { \ -+ .id = _id, \ -+ .type = CLK_DIVIDER, \ -+ .name = _name, \ -+ .data = { \ -+ .div = { \ -+ .parent_id = _parent_id, \ -+ .reg = _reg, \ -+ .bit_shift = _shift, \ -+ .bit_width = _width, \ -+ .div_table = _div_table, \ -+ }, \ -+ }, \ -+ } ++ /* Unmasking the IRQ */ ++ if (set) ++ gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d)); + -+#define FIXED_FACTOR_CLK(_id, _name, _parent_id, _mult, _div) \ -+ { \ -+ .id = _id, \ -+ .type = CLK_FIXED_FACTOR, \ -+ .name = _name, \ -+ .data = { .factor = { .parent_id = _parent_id, .mult = _mult, .div = _div, } }, \ ++ 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); ++ ++ /* Masking the IRQ */ ++ if (!set) ++ gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(d)); ++} ++ ++static void aspeed_ltpi_gpio_irq_mask(struct irq_data *d) ++{ ++ aspeed_ltpi_gpio_irq_set_mask(d, false); ++} ++ ++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; + } + -+#define GATE_CLK(_id, _type, _name, _parent_id, _reg, _bit, _flags) \ -+ { \ -+ .id = _id, \ -+ .type = _type, \ -+ .name = _name, \ -+ .data = { \ -+ .gate = { \ -+ .parent_id = _parent_id, \ -+ .reg = _reg, \ -+ .bit = _bit, \ -+ .flags = _flags, \ -+ }, \ -+ }, \ ++ 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 const struct ast2700_clk_info ast2700_scu0_clk_info[] __initconst = { -+ FIXED_CLK(SCU0_CLKIN, "soc0-clkin", 25 * HZ_PER_MHZ), -+ FIXED_CLK(SCU0_CLK_24M, "soc0-clk24Mhz", 24 * HZ_PER_MHZ), -+ FIXED_CLK(SCU0_CLK_192M, "soc0-clk192Mhz", 192 * HZ_PER_MHZ), -+ FIXED_CLK(SCU0_CLK_U2PHY_CLK12M, "u2phy_clk12m", 12 * HZ_PER_MHZ), -+ FIXED_DISPLAY_CLK(SCU0_CLK_D0, "d0clk", SCU0_D0CLK_PARAM), -+ FIXED_DISPLAY_CLK(SCU0_CLK_D1, "d1clk", SCU0_D1CLK_PARAM), -+ FIXED_DISPLAY_CLK(SCU0_CLK_CRT0, "crt0clk", SCU0_CRT0CLK_PARAM), -+ FIXED_DISPLAY_CLK(SCU0_CLK_CRT1, "crt1clk", SCU0_CRT1CLK_PARAM), -+ PLL_CLK(SCU0_CLK_HPLL, CLK_HPLL, "soc0-hpll", SCU0_CLKIN, SCU0_HPLL_PARAM), -+ PLL_CLK(SCU0_CLK_DPLL, CLK_PLL, "soc0-dpll", SCU0_CLKIN, SCU0_DPLL_PARAM), -+ PLL_CLK(SCU0_CLK_MPLL, CLK_PLL, "soc0-mpll", SCU0_CLKIN, SCU0_MPLL_PARAM), -+ FIXED_FACTOR_CLK(SCU0_CLK_HPLL_DIV2, "soc0-hpll_div2", SCU0_CLK_HPLL, 1, 2), -+ FIXED_FACTOR_CLK(SCU0_CLK_HPLL_DIV4, "soc0-hpll_div4", SCU0_CLK_HPLL, 1, 4), -+ FIXED_FACTOR_CLK(SCU0_CLK_MPLL_DIV2, "soc0-mpll_div2", SCU0_CLK_MPLL, 1, 2), -+ FIXED_FACTOR_CLK(SCU0_CLK_MPLL_DIV4, "soc0-mpll_div4", SCU0_CLK_MPLL, 1, 4), -+ FIXED_FACTOR_CLK(SCU0_CLK_MPLL_DIV8, "soc0-mpll_div8", SCU0_CLK_MPLL, 1, 8), -+ FIXED_FACTOR_CLK(SCU0_CLK_AXI1, "axi1clk", SCU0_CLK_MPLL, 1, 4), -+ MUX_CLK(SCU0_CLK_PSP, "pspclk", psp_parent_ids, ARRAY_SIZE(psp_parent_ids), -+ psp_parent_hws, SCU0_HWSTRAP1, 2, 3), -+ FIXED_FACTOR_CLK(SCU0_CLK_AXI0, "axi0clk", SCU0_CLK_PSP, 1, 2), -+ MUX_CLK(SCU0_CLK_AHBMUX, "soc0-ahbmux", hclk_parent_ids, ARRAY_SIZE(hclk_parent_ids), -+ hclk_parent_hws, SCU0_HWSTRAP1, 7, 1), -+ MUX_CLK(SCU0_CLK_EMMCMUX, "emmcsrc-mux", emmc_parent_ids, ARRAY_SIZE(emmc_parent_ids), -+ emmc_parent_hws, SCU0_CLK_SEL1, 11, 1), -+ MUX_CLK(SCU0_CLK_MPHYSRC, "mphysrc", mphy_parent_ids, ARRAY_SIZE(mphy_parent_ids), -+ mphy_parent_hws, SCU0_CLK_SEL2, 18, 2), -+ MUX_CLK(SCU0_CLK_U2PHY_REFCLKSRC, "u2phy_refclksrc", u2phy_parent_ids, -+ ARRAY_SIZE(u2phy_parent_ids), u2phy_parent_hws, SCU0_CLK_SEL2, 23, 1), -+ MUX_CLK(SCU0_CLK_UART, "soc0-uartclk", uart_parent_ids, ARRAY_SIZE(uart_parent_ids), -+ uart_parent_hws, SCU0_CLK_SEL2, 14, 1), -+ PLL_CLK(SCU0_CLK_MPHY, CLK_MISC, "mphyclk", SCU0_CLK_MPHYSRC, SCU0_MPHYCLK_PARAM), -+ PLL_CLK(SCU0_CLK_U2PHY_REFCLK, CLK_MISC, "u2phy_refclk", SCU0_CLK_U2PHY_REFCLKSRC, -+ SCU0_CLK_SEL2), -+ DIVIDER_CLK(SCU0_CLK_AHB, "soc0-ahb", SCU0_CLK_AHBMUX, -+ SCU0_HWSTRAP1, 5, 2, ast2700_hclk_div_table), -+ DIVIDER_CLK(SCU0_CLK_EMMC, "emmcclk", SCU0_CLK_EMMCMUX, -+ SCU0_CLK_SEL1, 12, 3, ast2700_clk_div_table2), -+ DIVIDER_CLK(SCU0_CLK_APB, "soc0-apb", SCU0_CLK_AXI0, -+ SCU0_CLK_SEL1, 23, 3, ast2700_clk_div_table2), -+ DIVIDER_CLK(SCU0_CLK_HPLL_DIV_AHB, "soc0-hpll-ahb", SCU0_CLK_HPLL, -+ SCU0_HWSTRAP1, 5, 2, ast2700_hclk_div_table), -+ DIVIDER_CLK(SCU0_CLK_MPLL_DIV_AHB, "soc0-mpll-ahb", SCU0_CLK_MPLL, -+ SCU0_HWSTRAP1, 5, 2, ast2700_hclk_div_table), -+ DIVIDER_CLK(SCU0_CLK_UART4, "uart4clk", SCU0_CLK_UART, -+ SCU0_CLK_SEL2, 30, 1, ast2700_clk_uart_div_table), -+ GATE_CLK(SCU0_CLK_GATE_MCLK, CLK_GATE_ASPEED, "mclk-gate", SCU0_CLK_MPLL, -+ SCU0_CLK_STOP, 0, CLK_IS_CRITICAL), -+ GATE_CLK(SCU0_CLK_GATE_ECLK, CLK_GATE_ASPEED, "eclk-gate", -1, SCU0_CLK_STOP, 1, 0), -+ GATE_CLK(SCU0_CLK_GATE_2DCLK, CLK_GATE_ASPEED, "gclk-gate", -1, SCU0_CLK_STOP, 2, 0), -+ GATE_CLK(SCU0_CLK_GATE_VCLK, CLK_GATE_ASPEED, "vclk-gate", -1, SCU0_CLK_STOP, 3, 0), -+ GATE_CLK(SCU0_CLK_GATE_BCLK, CLK_GATE_ASPEED, "bclk-gate", -1, -+ SCU0_CLK_STOP, 4, CLK_IS_CRITICAL), -+ GATE_CLK(SCU0_CLK_GATE_VGA0CLK, CLK_GATE_ASPEED, "vga0clk-gate", -1, -+ SCU0_CLK_STOP, 5, CLK_IS_CRITICAL), -+ GATE_CLK(SCU0_CLK_GATE_REFCLK, CLK_GATE_ASPEED, "soc0-refclk-gate", SCU0_CLKIN, -+ SCU0_CLK_STOP, 6, CLK_IS_CRITICAL), -+ GATE_CLK(SCU0_CLK_GATE_PORTBUSB2CLK, CLK_GATE_ASPEED, "portb-usb2clk-gate", -1, -+ SCU0_CLK_STOP, 7, 0), -+ GATE_CLK(SCU0_CLK_GATE_UHCICLK, CLK_GATE_ASPEED, "uhciclk-gate", -1, SCU0_CLK_STOP, 9, 0), -+ GATE_CLK(SCU0_CLK_GATE_VGA1CLK, CLK_GATE_ASPEED, "vga1clk-gate", -1, -+ SCU0_CLK_STOP, 10, CLK_IS_CRITICAL), -+ GATE_CLK(SCU0_CLK_GATE_DDRPHYCLK, CLK_GATE_ASPEED, "ddrphy-gate", -1, -+ SCU0_CLK_STOP, 11, CLK_IS_CRITICAL), -+ GATE_CLK(SCU0_CLK_GATE_E2M0CLK, CLK_GATE_ASPEED, "e2m0clk-gate", -1, -+ SCU0_CLK_STOP, 12, CLK_IS_CRITICAL), -+ GATE_CLK(SCU0_CLK_GATE_HACCLK, CLK_GATE_ASPEED, "hacclk-gate", -1, SCU0_CLK_STOP, 13, 0), -+ GATE_CLK(SCU0_CLK_GATE_PORTAUSB2CLK, CLK_GATE_ASPEED, "porta-usb2clk-gate", -1, -+ SCU0_CLK_STOP, 14, 0), -+ GATE_CLK(SCU0_CLK_GATE_UART4CLK, CLK_GATE_ASPEED, "uart4clk-gate", SCU0_CLK_UART4, -+ SCU0_CLK_STOP, 15, CLK_IS_CRITICAL), -+ GATE_CLK(SCU0_CLK_GATE_SLICLK, CLK_GATE_ASPEED, "soc0-sliclk-gate", -1, -+ SCU0_CLK_STOP, 16, CLK_IS_CRITICAL), -+ GATE_CLK(SCU0_CLK_GATE_DACCLK, CLK_GATE_ASPEED, "dacclk-gate", -1, -+ SCU0_CLK_STOP, 17, CLK_IS_CRITICAL), -+ GATE_CLK(SCU0_CLK_GATE_DP, CLK_GATE_ASPEED, "dpclk-gate", -1, -+ SCU0_CLK_STOP, 18, CLK_IS_CRITICAL), -+ GATE_CLK(SCU0_CLK_GATE_E2M1CLK, CLK_GATE_ASPEED, "e2m1clk-gate", -1, -+ SCU0_CLK_STOP, 19, CLK_IS_CRITICAL), -+ GATE_CLK(SCU0_CLK_GATE_CRT0CLK, CLK_GATE_ASPEED, "crt0clk-gate", -1, -+ SCU0_CLK_STOP, 20, 0), -+ GATE_CLK(SCU0_CLK_GATE_CRT1CLK, CLK_GATE_ASPEED, "crt1clk-gate", -1, -+ SCU0_CLK_STOP, 21, 0), -+ GATE_CLK(SCU0_CLK_GATE_ECDSACLK, CLK_GATE_ASPEED, "eccclk-gate", -1, -+ SCU0_CLK_STOP, 23, 0), -+ GATE_CLK(SCU0_CLK_GATE_RSACLK, CLK_GATE_ASPEED, "rsaclk-gate", -1, -+ SCU0_CLK_STOP, 24, 0), -+ GATE_CLK(SCU0_CLK_GATE_RVAS0CLK, CLK_GATE_ASPEED, "rvas0clk-gate", -1, -+ SCU0_CLK_STOP, 25, 0), -+ GATE_CLK(SCU0_CLK_GATE_UFSCLK, CLK_GATE_ASPEED, "ufsclk-gate", -1, -+ SCU0_CLK_STOP, 26, 0), -+ GATE_CLK(SCU0_CLK_GATE_EMMCCLK, CLK_GATE_ASPEED, "emmcclk-gate", SCU0_CLK_EMMC, -+ SCU0_CLK_STOP, 27, 0), -+ GATE_CLK(SCU0_CLK_GATE_RVAS1CLK, CLK_GATE_ASPEED, "rvas1clk-gate", -1, -+ SCU0_CLK_STOP, 28, 0), -+}; ++static void aspeed_ltpi_gpio_irq_print_chip(struct irq_data *d, ++ struct seq_file *p) ++{ ++ struct aspeed_ltpi_gpio *gpio; ++ int offset; + -+static const struct ast2700_clk_info ast2700_scu1_clk_info[] __initconst = { -+ FIXED_CLK(SCU1_CLKIN, "soc1-clkin", 25 * HZ_PER_MHZ), -+ 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_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), -+ DIVIDER_CLK(SCU1_CLK_APB, "soc1-apb", SCU1_CLK_HPLL, -+ SCU1_CLK_SEL1, 18, 3, ast2700_clk_div_table2), -+ DIVIDER_CLK(SCU1_CLK_RMII, "rmii", SCU1_CLK_HPLL, -+ SCU1_CLK_SEL1, 21, 3, ast2700_rmii_div_table), -+ DIVIDER_CLK(SCU1_CLK_RGMII, "rgmii", SCU1_CLK_HPLL, -+ SCU1_CLK_SEL1, 25, 3, ast2700_rgmii_div_table), -+ DIVIDER_CLK(SCU1_CLK_MACHCLK, "machclk", SCU1_CLK_HPLL, -+ SCU1_CLK_SEL1, 29, 3, ast2700_clk_div_table), -+ DIVIDER_CLK(SCU1_CLK_APLL_DIVN, "soc1-apll_divn", -+ SCU1_CLK_APLL, SCU1_CLK_SEL2, 8, 3, ast2700_clk_div_table), -+ DIVIDER_CLK(SCU1_CLK_AHB, "soc1-ahb", SCU1_CLK_HPLL, -+ SCU1_CLK_SEL2, 20, 3, ast2700_clk_div_table), -+ DIVIDER_CLK(SCU1_CLK_I3C, "soc1-i3c", SCU1_CLK_HPLL, -+ SCU1_CLK_SEL2, 23, 3, ast2700_clk_div_table), -+ MUX_CLK(SCU1_CLK_SDMUX, "sdclk-mux", sdclk_parent_ids, ARRAY_SIZE(sdclk_parent_ids), -+ sdclk_parent_hws, SCU1_CLK_SEL1, 13, 1), -+ MUX_CLK(SCU1_CLK_UXCLK, "uxclk", uxclk_parent_ids, ARRAY_SIZE(uxclk_parent_ids), -+ 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), -+ 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), -+ PLL_CLK(SCU1_CLK_HUARTX, CLK_UART_PLL, "huartxclk", SCU1_CLK_HUXCLK, SCU1_HUXCLK_CTRL), -+ MUX_CLK(SCU1_CLK_UART0, "uart0clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 0, 1), -+ MUX_CLK(SCU1_CLK_UART1, "uart1clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 1, 1), -+ MUX_CLK(SCU1_CLK_UART2, "uart2clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 2, 1), -+ MUX_CLK(SCU1_CLK_UART3, "uart3clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 3, 1), -+ MUX_CLK(SCU1_CLK_UART5, "uart5clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 5, 1), -+ MUX_CLK(SCU1_CLK_UART6, "uart6clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 6, 1), -+ MUX_CLK(SCU1_CLK_UART7, "uart7clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 7, 1), -+ MUX_CLK(SCU1_CLK_UART8, "uart8clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 8, 1), -+ MUX_CLK(SCU1_CLK_UART9, "uart9clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 9, 1), -+ MUX_CLK(SCU1_CLK_UART10, "uart10clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 10, 1), -+ MUX_CLK(SCU1_CLK_UART11, "uart11clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 11, 1), -+ MUX_CLK(SCU1_CLK_UART12, "uart12clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 12, 1), -+ FIXED_FACTOR_CLK(SCU1_CLK_UART13, "uart13clk", SCU1_CLK_HUARTX, 1, 1), -+ FIXED_FACTOR_CLK(SCU1_CLK_UART14, "uart14clk", SCU1_CLK_HUARTX, 1, 1), -+ GATE_CLK(SCU1_CLK_MAC0RCLK, CLK_GATE, "mac0rclk-gate", SCU1_CLK_RMII, -+ SCU1_MAC12_CLK_DLY, 29, 0), -+ GATE_CLK(SCU1_CLK_MAC1RCLK, CLK_GATE, "mac1rclk-gate", SCU1_CLK_RMII, -+ SCU1_MAC12_CLK_DLY, 30, 0), -+ GATE_CLK(SCU1_CLK_GATE_LCLK0, CLK_GATE_ASPEED, "lclk0-gate", -1, -+ SCU1_CLK_STOP, 0, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_LCLK1, CLK_GATE_ASPEED, "lclk1-gate", -1, -+ SCU1_CLK_STOP, 1, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_ESPI0CLK, CLK_GATE_ASPEED, "espi0clk-gate", -1, -+ SCU1_CLK_STOP, 2, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_ESPI1CLK, CLK_GATE_ASPEED, "espi1clk-gate", -1, -+ SCU1_CLK_STOP, 3, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_SDCLK, CLK_GATE_ASPEED, "sdclk-gate", SCU1_CLK_SDCLK, -+ SCU1_CLK_STOP, 4, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_IPEREFCLK, CLK_GATE_ASPEED, "soc1-iperefclk-gate", -1, -+ SCU1_CLK_STOP, 5, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_REFCLK, CLK_GATE_ASPEED, "soc1-refclk-gate", -1, -+ SCU1_CLK_STOP, 6, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_LPCHCLK, CLK_GATE_ASPEED, "lpchclk-gate", -1, -+ SCU1_CLK_STOP, 7, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_MAC0CLK, CLK_GATE_ASPEED, "mac0clk-gate", -1, -+ SCU1_CLK_STOP, 8, 0), -+ GATE_CLK(SCU1_CLK_GATE_MAC1CLK, CLK_GATE_ASPEED, "mac1clk-gate", -1, -+ SCU1_CLK_STOP, 9, 0), -+ GATE_CLK(SCU1_CLK_GATE_MAC2CLK, CLK_GATE_ASPEED, "mac2clk-gate", -1, -+ SCU1_CLK_STOP, 10, 0), -+ GATE_CLK(SCU1_CLK_GATE_UART0CLK, CLK_GATE_ASPEED, "uart0clk-gate", SCU1_CLK_UART0, -+ SCU1_CLK_STOP, 11, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_UART1CLK, CLK_GATE_ASPEED, "uart1clk-gate", SCU1_CLK_UART1, -+ SCU1_CLK_STOP, 12, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_UART2CLK, CLK_GATE_ASPEED, "uart2clk-gate", SCU1_CLK_UART2, -+ SCU1_CLK_STOP, 13, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_UART3CLK, CLK_GATE_ASPEED, "uart3clk-gate", SCU1_CLK_UART3, -+ SCU1_CLK_STOP, 14, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_I2CCLK, CLK_GATE_ASPEED, "i2cclk-gate", -1, SCU1_CLK_STOP, 15, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C0CLK, CLK_GATE_ASPEED, "i3c0clk-gate", SCU1_CLK_I3C, -+ SCU1_CLK_STOP, 16, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C1CLK, CLK_GATE_ASPEED, "i3c1clk-gate", SCU1_CLK_I3C, -+ SCU1_CLK_STOP, 17, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C2CLK, CLK_GATE_ASPEED, "i3c2clk-gate", SCU1_CLK_I3C, -+ SCU1_CLK_STOP, 18, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C3CLK, CLK_GATE_ASPEED, "i3c3clk-gate", SCU1_CLK_I3C, -+ SCU1_CLK_STOP, 19, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C4CLK, CLK_GATE_ASPEED, "i3c4clk-gate", SCU1_CLK_I3C, -+ SCU1_CLK_STOP, 20, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C5CLK, CLK_GATE_ASPEED, "i3c5clk-gate", SCU1_CLK_I3C, -+ SCU1_CLK_STOP, 21, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C6CLK, CLK_GATE_ASPEED, "i3c6clk-gate", SCU1_CLK_I3C, -+ SCU1_CLK_STOP, 22, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C7CLK, CLK_GATE_ASPEED, "i3c7clk-gate", SCU1_CLK_I3C, -+ SCU1_CLK_STOP, 23, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C8CLK, CLK_GATE_ASPEED, "i3c8clk-gate", SCU1_CLK_I3C, -+ SCU1_CLK_STOP, 24, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C9CLK, CLK_GATE_ASPEED, "i3c9clk-gate", SCU1_CLK_I3C, -+ SCU1_CLK_STOP, 25, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C10CLK, CLK_GATE_ASPEED, "i3c10clk-gate", SCU1_CLK_I3C, -+ SCU1_CLK_STOP, 26, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C11CLK, CLK_GATE_ASPEED, "i3c11clk-gate", SCU1_CLK_I3C, -+ SCU1_CLK_STOP, 27, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C12CLK, CLK_GATE_ASPEED, "i3c12clk-gate", SCU1_CLK_I3C, -+ SCU1_CLK_STOP, 28, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C13CLK, CLK_GATE_ASPEED, "i3c13clk-gate", SCU1_CLK_I3C, -+ SCU1_CLK_STOP, 29, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C14CLK, CLK_GATE_ASPEED, "i3c14clk-gate", SCU1_CLK_I3C, -+ SCU1_CLK_STOP, 30, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C15CLK, CLK_GATE_ASPEED, "i3c15clk-gate", SCU1_CLK_I3C, -+ SCU1_CLK_STOP, 31, 0), -+ GATE_CLK(SCU1_CLK_GATE_UART5CLK, CLK_GATE_ASPEED, "uart5clk-gate", SCU1_CLK_UART5, -+ SCU1_CLK_STOP2, 0, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_UART6CLK, CLK_GATE_ASPEED, "uart6clk-gate", SCU1_CLK_UART6, -+ SCU1_CLK_STOP2, 1, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_UART7CLK, CLK_GATE_ASPEED, "uart7clk-gate", SCU1_CLK_UART7, -+ SCU1_CLK_STOP2, 2, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_UART8CLK, CLK_GATE_ASPEED, "uart8clk-gate", SCU1_CLK_UART8, -+ SCU1_CLK_STOP2, 3, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_UART9CLK, CLK_GATE_ASPEED, "uart9clk-gate", SCU1_CLK_UART9, -+ SCU1_CLK_STOP2, 4, 0), -+ GATE_CLK(SCU1_CLK_GATE_UART10CLK, CLK_GATE_ASPEED, "uart10clk-gate", SCU1_CLK_UART10, -+ SCU1_CLK_STOP2, 5, 0), -+ GATE_CLK(SCU1_CLK_GATE_UART11CLK, CLK_GATE_ASPEED, "uart11clk-gate", SCU1_CLK_UART11, -+ SCU1_CLK_STOP2, 6, 0), -+ GATE_CLK(SCU1_CLK_GATE_UART12CLK, CLK_GATE_ASPEED, "uart12clk-gate", SCU1_CLK_UART12, -+ SCU1_CLK_STOP2, 7, 0), -+ GATE_CLK(SCU1_CLK_GATE_FSICLK, CLK_GATE_ASPEED, "fsiclk-gate", -1, SCU1_CLK_STOP2, 8, 0), -+ GATE_CLK(SCU1_CLK_GATE_LTPIPHYCLK, CLK_GATE_ASPEED, "ltpiphyclk-gate", -1, -+ SCU1_CLK_STOP2, 9, 0), -+ GATE_CLK(SCU1_CLK_GATE_LTPICLK, CLK_GATE_ASPEED, "ltpiclk-gate", -1, -+ SCU1_CLK_STOP2, 10, 0), -+ GATE_CLK(SCU1_CLK_GATE_VGALCLK, CLK_GATE_ASPEED, "vgalclk-gate", -1, -+ SCU1_CLK_STOP2, 11, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_UHCICLK, CLK_GATE_ASPEED, "usbuartclk-gate", -1, -+ SCU1_CLK_STOP2, 12, 0), -+ GATE_CLK(SCU1_CLK_GATE_CANCLK, CLK_GATE_ASPEED, "canclk-gate", SCU1_CLK_CAN, -+ SCU1_CLK_STOP2, 13, 0), -+ GATE_CLK(SCU1_CLK_GATE_PCICLK, CLK_GATE_ASPEED, "pciclk-gate", -1, -+ SCU1_CLK_STOP2, 14, 0), -+ GATE_CLK(SCU1_CLK_GATE_SLICLK, CLK_GATE_ASPEED, "soc1-sliclk-gate", -1, -+ SCU1_CLK_STOP2, 15, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_E2MCLK, CLK_GATE_ASPEED, "soc1-e2m-gate", -1, -+ SCU1_CLK_STOP2, 16, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_PORTCUSB2CLK, CLK_GATE_ASPEED, "portcusb2-gate", -1, -+ SCU1_CLK_STOP2, 17, 0), -+ GATE_CLK(SCU1_CLK_GATE_PORTDUSB2CLK, CLK_GATE_ASPEED, "portdusb2-gate", -1, -+ SCU1_CLK_STOP2, 18, 0), -+ GATE_CLK(SCU1_CLK_GATE_LTPI1TXCLK, CLK_GATE_ASPEED, "ltp1tx-gate", -1, -+ SCU1_CLK_STOP2, 19, 0), ++ 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 const struct ast2700_clk_info ast2755_scu1_clk_info[] __initconst = { -+ FIXED_CLK(SCU1_CLKIN, "soc1-clkin", 25 * HZ_PER_MHZ), -+ 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_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), -+ DIVIDER_CLK(SCU1_CLK_APB, "soc1-apb", SCU1_CLK_HPLL, -+ SCU1_CLK_SEL1, 18, 3, ast2700_clk_div_table2), -+ DIVIDER_CLK(SCU1_CLK_RMII, "rmii", SCU1_CLK_HPLL, -+ SCU1_CLK_SEL1, 21, 3, ast2700_rmii_div_table), -+ DIVIDER_CLK(SCU1_CLK_RGMII, "rgmii", SCU1_CLK_HPLL, -+ SCU1_CLK_SEL1, 25, 3, ast2700_rgmii_div_table), -+ DIVIDER_CLK(SCU1_CLK_MACHCLK, "machclk", SCU1_CLK_HPLL, -+ SCU1_CLK_SEL1, 29, 3, ast2700_clk_div_table), -+ DIVIDER_CLK(SCU1_CLK_APLL_DIVN, "soc1-apll_divn", -+ SCU1_CLK_APLL, SCU1_CLK_SEL2, 8, 3, ast2700_clk_div_table), -+ DIVIDER_CLK(SCU1_CLK_AHB, "soc1-ahb", SCU1_CLK_HPLL, -+ SCU1_CLK_SEL2, 20, 3, ast2700_clk_div_table), -+ DIVIDER_CLK(SCU1_CLK_I3C, "soc1-i3c", SCU1_CLK_HPLL, -+ SCU1_CLK_SEL2, 23, 3, ast2700_clk_div_table), -+ MUX_CLK(SCU1_CLK_SDMUX, "sdclk-mux", sdclk_parent_ids, ARRAY_SIZE(sdclk_parent_ids), -+ sdclk_parent_hws, SCU1_CLK_SEL1, 13, 1), -+ MUX_CLK(SCU1_CLK_UXCLK, "uxclk", uxclk_parent_ids, ARRAY_SIZE(uxclk_parent_ids), -+ 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), -+ 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), -+ PLL_CLK(SCU1_CLK_HUARTX, CLK_UART_PLL, "huartxclk", SCU1_CLK_HUXCLK, SCU1_HUXCLK_CTRL), -+ MUX_CLK(SCU1_CLK_UART0, "uart0clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 0, 1), -+ MUX_CLK(SCU1_CLK_UART1, "uart1clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 1, 1), -+ MUX_CLK(SCU1_CLK_UART2, "uart2clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 2, 1), -+ MUX_CLK(SCU1_CLK_UART3, "uart3clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 3, 1), -+ MUX_CLK(SCU1_CLK_UART5, "uart5clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 5, 1), -+ MUX_CLK(SCU1_CLK_UART6, "uart6clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 6, 1), -+ MUX_CLK(SCU1_CLK_UART7, "uart7clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 7, 1), -+ MUX_CLK(SCU1_CLK_UART8, "uart8clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 8, 1), -+ MUX_CLK(SCU1_CLK_UART9, "uart9clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 9, 1), -+ MUX_CLK(SCU1_CLK_UART10, "uart10clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 10, 1), -+ MUX_CLK(SCU1_CLK_UART11, "uart11clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 11, 1), -+ MUX_CLK(SCU1_CLK_UART12, "uart12clk", uartx_parent_ids, ARRAY_SIZE(uartx_parent_ids), -+ uartx_parent_hws, SCU1_CLK_SEL1, 12, 1), -+ FIXED_FACTOR_CLK(SCU1_CLK_UART13, "uart13clk", SCU1_CLK_HUARTX, 1, 1), -+ FIXED_FACTOR_CLK(SCU1_CLK_UART14, "uart14clk", SCU1_CLK_HUARTX, 1, 1), -+ GATE_CLK(SCU1_CLK_MAC0RCLK, CLK_GATE, "mac0rclk-gate", SCU1_CLK_RMII, -+ SCU1_MAC12_CLK_DLY, 29, 0), -+ GATE_CLK(SCU1_CLK_MAC1RCLK, CLK_GATE, "mac1rclk-gate", SCU1_CLK_RMII, -+ SCU1_MAC12_CLK_DLY, 30, 0), -+ GATE_CLK(SCU1_CLK_GATE_LCLK0, CLK_GATE_ASPEED, "lclk0-gate", -1, -+ SCU1_CLK_STOP, 0, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_LCLK1, CLK_GATE_ASPEED, "lclk1-gate", -1, -+ AST2755_SCU1_CLK_STOP, 1, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_ESPI0CLK, CLK_GATE_ASPEED, "espi0clk-gate", -1, -+ AST2755_SCU1_CLK_STOP, 2, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_ESPI1CLK, CLK_GATE_ASPEED, "espi1clk-gate", -1, -+ AST2755_SCU1_CLK_STOP, 3, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_SDCLK, CLK_GATE_ASPEED, "sdclk-gate", SCU1_CLK_SDCLK, -+ AST2755_SCU1_CLK_STOP, 4, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_IPEREFCLK, CLK_GATE_ASPEED, "soc1-iperefclk-gate", -1, -+ AST2755_SCU1_CLK_STOP, 5, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_REFCLK, CLK_GATE_ASPEED, "soc1-refclk-gate", -1, -+ AST2755_SCU1_CLK_STOP, 6, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_LPCHCLK, CLK_GATE_ASPEED, "lpchclk-gate", -1, -+ AST2755_SCU1_CLK_STOP, 7, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_MAC0CLK, CLK_GATE_ASPEED, "mac0clk-gate", -1, -+ AST2755_SCU1_CLK_STOP, 8, 0), -+ GATE_CLK(SCU1_CLK_GATE_MAC1CLK, CLK_GATE_ASPEED, "mac1clk-gate", -1, -+ AST2755_SCU1_CLK_STOP, 9, 0), -+ GATE_CLK(SCU1_CLK_GATE_MAC2CLK, CLK_GATE_ASPEED, "mac2clk-gate", -1, -+ AST2755_SCU1_CLK_STOP, 10, 0), -+ GATE_CLK(SCU1_CLK_GATE_UART0CLK, CLK_GATE_ASPEED, "uart0clk-gate", SCU1_CLK_UART0, -+ AST2755_SCU1_CLK_STOP, 11, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_UART1CLK, CLK_GATE_ASPEED, "uart1clk-gate", SCU1_CLK_UART1, -+ AST2755_SCU1_CLK_STOP, 12, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_UART2CLK, CLK_GATE_ASPEED, "uart2clk-gate", SCU1_CLK_UART2, -+ AST2755_SCU1_CLK_STOP, 13, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_UART3CLK, CLK_GATE_ASPEED, "uart3clk-gate", SCU1_CLK_UART3, -+ AST2755_SCU1_CLK_STOP, 14, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_I2CCLK, CLK_GATE_ASPEED, "i2cclk-gate", -1, SCU1_CLK_STOP, 15, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C0CLK, CLK_GATE_ASPEED, "i3c0clk-gate", SCU1_CLK_I3C, -+ AST2755_SCU1_CLK_STOP, 16, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C1CLK, CLK_GATE_ASPEED, "i3c1clk-gate", SCU1_CLK_I3C, -+ AST2755_SCU1_CLK_STOP, 17, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C2CLK, CLK_GATE_ASPEED, "i3c2clk-gate", SCU1_CLK_I3C, -+ AST2755_SCU1_CLK_STOP, 18, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C3CLK, CLK_GATE_ASPEED, "i3c3clk-gate", SCU1_CLK_I3C, -+ AST2755_SCU1_CLK_STOP, 19, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C4CLK, CLK_GATE_ASPEED, "i3c4clk-gate", SCU1_CLK_I3C, -+ AST2755_SCU1_CLK_STOP, 20, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C5CLK, CLK_GATE_ASPEED, "i3c5clk-gate", SCU1_CLK_I3C, -+ AST2755_SCU1_CLK_STOP, 21, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C6CLK, CLK_GATE_ASPEED, "i3c6clk-gate", SCU1_CLK_I3C, -+ AST2755_SCU1_CLK_STOP, 22, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C7CLK, CLK_GATE_ASPEED, "i3c7clk-gate", SCU1_CLK_I3C, -+ AST2755_SCU1_CLK_STOP, 23, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C8CLK, CLK_GATE_ASPEED, "i3c8clk-gate", SCU1_CLK_I3C, -+ AST2755_SCU1_CLK_STOP, 24, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C9CLK, CLK_GATE_ASPEED, "i3c9clk-gate", SCU1_CLK_I3C, -+ AST2755_SCU1_CLK_STOP, 25, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C10CLK, CLK_GATE_ASPEED, "i3c10clk-gate", SCU1_CLK_I3C, -+ AST2755_SCU1_CLK_STOP, 26, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C11CLK, CLK_GATE_ASPEED, "i3c11clk-gate", SCU1_CLK_I3C, -+ AST2755_SCU1_CLK_STOP, 27, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C12CLK, CLK_GATE_ASPEED, "i3c12clk-gate", SCU1_CLK_I3C, -+ AST2755_SCU1_CLK_STOP, 28, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C13CLK, CLK_GATE_ASPEED, "i3c13clk-gate", SCU1_CLK_I3C, -+ AST2755_SCU1_CLK_STOP, 29, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C14CLK, CLK_GATE_ASPEED, "i3c14clk-gate", SCU1_CLK_I3C, -+ AST2755_SCU1_CLK_STOP, 30, 0), -+ GATE_CLK(SCU1_CLK_GATE_I3C15CLK, CLK_GATE_ASPEED, "i3c15clk-gate", SCU1_CLK_I3C, -+ AST2755_SCU1_CLK_STOP, 31, 0), -+ GATE_CLK(SCU1_CLK_GATE_UART5CLK, CLK_GATE_ASPEED, "uart5clk-gate", SCU1_CLK_UART5, -+ AST2755_SCU1_CLK_STOP, 0, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_UART6CLK, CLK_GATE_ASPEED, "uart6clk-gate", SCU1_CLK_UART6, -+ AST2755_SCU1_CLK_STOP, 1, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_UART7CLK, CLK_GATE_ASPEED, "uart7clk-gate", SCU1_CLK_UART7, -+ AST2755_SCU1_CLK_STOP, 2, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_UART8CLK, CLK_GATE_ASPEED, "uart8clk-gate", SCU1_CLK_UART8, -+ AST2755_SCU1_CLK_STOP, 3, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_UART9CLK, CLK_GATE_ASPEED, "uart9clk-gate", SCU1_CLK_UART9, -+ AST2755_SCU1_CLK_STOP, 4, 0), -+ GATE_CLK(SCU1_CLK_GATE_UART10CLK, CLK_GATE_ASPEED, "uart10clk-gate", SCU1_CLK_UART10, -+ AST2755_SCU1_CLK_STOP, 5, 0), -+ GATE_CLK(SCU1_CLK_GATE_UART11CLK, CLK_GATE_ASPEED, "uart11clk-gate", SCU1_CLK_UART11, -+ AST2755_SCU1_CLK_STOP, 6, 0), -+ GATE_CLK(SCU1_CLK_GATE_UART12CLK, CLK_GATE_ASPEED, "uart12clk-gate", SCU1_CLK_UART12, -+ AST2755_SCU1_CLK_STOP, 7, 0), -+ GATE_CLK(SCU1_CLK_GATE_FSICLK, CLK_GATE_ASPEED, "fsiclk-gate", -1, SCU1_CLK_STOP2, 8, 0), -+ GATE_CLK(SCU1_CLK_GATE_LTPIPHYCLK, CLK_GATE_ASPEED, "ltpiphyclk-gate", -1, -+ AST2755_SCU1_CLK_STOP, 9, 0), -+ GATE_CLK(SCU1_CLK_GATE_LTPICLK, CLK_GATE_ASPEED, "ltpiclk-gate", -1, -+ AST2755_SCU1_CLK_STOP, 10, 0), -+ GATE_CLK(SCU1_CLK_GATE_VGALCLK, CLK_GATE_ASPEED, "vgalclk-gate", -1, -+ AST2755_SCU1_CLK_STOP, 11, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_UHCICLK, CLK_GATE_ASPEED, "usbuartclk-gate", -1, -+ AST2755_SCU1_CLK_STOP, 12, 0), -+ GATE_CLK(SCU1_CLK_GATE_CANCLK, CLK_GATE_ASPEED, "canclk-gate", SCU1_CLK_CAN, -+ AST2755_SCU1_CLK_STOP, 13, 0), -+ GATE_CLK(SCU1_CLK_GATE_PCICLK, CLK_GATE_ASPEED, "pciclk-gate", -1, -+ AST2755_SCU1_CLK_STOP, 14, 0), -+ GATE_CLK(SCU1_CLK_GATE_SLICLK, CLK_GATE_ASPEED, "soc1-sliclk-gate", -1, -+ AST2755_SCU1_CLK_STOP, 15, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_E2MCLK, CLK_GATE_ASPEED, "soc1-e2m-gate", -1, -+ AST2755_SCU1_CLK_STOP, 16, CLK_IS_CRITICAL), -+ GATE_CLK(SCU1_CLK_GATE_PORTCUSB2CLK, CLK_GATE_ASPEED, "portcusb2-gate", -1, -+ AST2755_SCU1_CLK_STOP, 17, 0), -+ GATE_CLK(SCU1_CLK_GATE_PORTDUSB2CLK, CLK_GATE_ASPEED, "portdusb2-gate", -1, -+ AST2755_SCU1_CLK_STOP, 18, 0), -+ GATE_CLK(SCU1_CLK_GATE_LTPI1TXCLK, CLK_GATE_ASPEED, "ltp1tx-gate", -1, -+ AST2755_SCU1_CLK_STOP, 19, 0), -+}; -+ -+static struct clk_hw *ast2700_clk_hw_register_fixed_display(void __iomem *reg, const char *name, -+ struct ast2700_clk_ctrl *clk_ctrl) ++static int aspeed_ltpi_gpio_setup_irqs(struct aspeed_ltpi_gpio *gpio, ++ struct platform_device *pdev) +{ -+ unsigned int mult, div, r, n; -+ u32 xdclk; -+ u32 val; ++ int rc; ++ struct gpio_irq_chip *irq; + -+ val = readl(clk_ctrl->base + SCU0_CLK_SEL2); -+ if (val & BIT(29)) -+ xdclk = 800 * HZ_PER_MHZ; -+ else -+ xdclk = 1000 * HZ_PER_MHZ; ++ rc = platform_get_irq(pdev, 0); ++ if (rc < 0) ++ return rc; + -+ val = readl(reg); -+ r = val & GENMASK(15, 0); -+ n = (val >> 16) & GENMASK(15, 0); -+ mult = r; -+ div = 2 * n; ++ gpio->irq = rc; + -+ return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL, 0, (xdclk * mult) / div); ++ 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 struct clk_hw *ast2700_clk_hw_register_hpll(void __iomem *reg, -+ const char *name, const struct clk_hw *parent_hw, -+ struct ast2700_clk_ctrl *clk_ctrl) ++static int aspeed_ltpi_gpio_reset_tolerance(struct gpio_chip *chip, ++ unsigned int offset, bool enable) +{ -+ unsigned int mult, div; -+ u32 val; ++ struct aspeed_ltpi_gpio *gpio = gpiochip_get_data(chip); ++ unsigned long flags; ++ void __iomem *reg; + -+ val = readl(clk_ctrl->base + SCU0_HWSTRAP1); -+ if ((readl(clk_ctrl->base) & REVISION_ID) && (val & BIT(3))) { -+ switch ((val & GENMASK(4, 2)) >> 2) { -+ case 2: -+ return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL, -+ 0, 1800 * HZ_PER_MHZ); -+ case 3: -+ return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL, -+ 0, 1700 * HZ_PER_MHZ); -+ case 6: -+ return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL, -+ 0, 1200 * HZ_PER_MHZ); -+ case 7: -+ return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL, -+ 0, 800 * HZ_PER_MHZ); -+ default: -+ return ERR_PTR(-EINVAL); -+ } -+ } else if ((val & GENMASK(3, 2)) != 0) { -+ switch ((val & GENMASK(3, 2)) >> 2) { -+ case 1: -+ return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL, -+ 0, 1900 * HZ_PER_MHZ); -+ case 2: -+ return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL, -+ 0, 1800 * HZ_PER_MHZ); -+ case 3: -+ return devm_clk_hw_register_fixed_rate(clk_ctrl->dev, name, NULL, -+ 0, 1700 * HZ_PER_MHZ); -+ default: -+ return ERR_PTR(-EINVAL); -+ } -+ } else { -+ val = readl(reg); ++ reg = gpio->base + LTPI_GPIO_CTRL_REG_OFFSET(offset >> 1); + -+ if (val & BIT(24)) { -+ /* Pass through mode */ -+ mult = 1; -+ div = 1; -+ } else { -+ u32 m = val & 0x1fff; -+ u32 n = (val >> 13) & 0x3f; -+ u32 p = (val >> 19) & 0xf; ++ raw_spin_lock_irqsave(&gpio->lock, flags); + -+ mult = (m + 1) / (2 * (n + 1)); -+ div = p + 1; -+ } -+ } ++ if (enable) ++ ast_write_bits(reg, LTPI_GPIO_RST_TOLERANCE, 1); ++ else ++ ast_clr_bits(reg, LTPI_GPIO_RST_TOLERANCE); + -+ return devm_clk_hw_register_fixed_factor_parent_hw(clk_ctrl->dev, name, -+ parent_hw, 0, mult, div); ++ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ ++ return 0; +} + -+static struct clk_hw *ast2700_clk_hw_register_pll(int clk_idx, void __iomem *reg, -+ const char *name, const struct clk_hw *parent_hw, -+ struct ast2700_clk_ctrl *clk_ctrl) ++static int aspeed_ltpi_gpio_set_config(struct gpio_chip *chip, ++ unsigned int offset, ++ unsigned long config) +{ -+ int scu = clk_ctrl->clk_data->scu; -+ unsigned int mult, div; -+ u32 val = readl(reg); -+ -+ if (val & BIT(24)) { -+ /* Pass through mode */ -+ mult = 1; -+ div = 1; -+ } else { -+ u32 m = val & 0x1fff; -+ u32 n = (val >> 13) & 0x3f; -+ u32 p = (val >> 19) & 0xf; ++ unsigned long param = pinconf_to_config_param(config); ++ u32 arg = pinconf_to_config_argument(config); + -+ if (scu) { -+ mult = (m + 1) / (n + 1); -+ div = p + 1; -+ } else { -+ if (clk_idx == SCU0_CLK_MPLL) { -+ mult = m / (n + 1); -+ div = p + 1; -+ } else { -+ mult = (m + 1) / (2 * (n + 1)); -+ div = p + 1; -+ } -+ } -+ } ++ if (param == PIN_CONFIG_PERSIST_STATE) ++ return aspeed_ltpi_gpio_reset_tolerance(chip, offset, arg); + -+ return devm_clk_hw_register_fixed_factor_parent_hw(clk_ctrl->dev, name, -+ parent_hw, 0, mult, div); ++ return -EOPNOTSUPP; +} + -+static struct clk_hw *ast2700_clk_hw_register_uartpll(void __iomem *reg, const char *name, -+ const struct clk_hw *parent_hw, -+ struct ast2700_clk_ctrl *clk_ctrl) -+{ -+ unsigned int mult, div; -+ u32 val = readl(reg); -+ u32 r = val & 0xff; -+ u32 n = (val >> 8) & 0x3ff; -+ -+ mult = r; -+ div = n * 2; ++static const struct of_device_id aspeed_ltpi_gpio_of_table[] = { ++ { .compatible = "aspeed,ast2700-ltpi-gpio" }, ++ {} ++}; + -+ return devm_clk_hw_register_fixed_factor_parent_hw(clk_ctrl->dev, name, -+ parent_hw, 0, mult, div); -+} ++MODULE_DEVICE_TABLE(of, aspeed_ltpi_gpio_of_table); + -+static struct clk_hw *ast2700_clk_hw_register_misc(int clk_idx, void __iomem *reg, -+ const char *name, const struct clk_hw *parent_hw, -+ struct ast2700_clk_ctrl *clk_ctrl) ++static int __init aspeed_ltpi_gpio_probe(struct platform_device *pdev) +{ -+ u32 div = 0; -+ -+ if (clk_idx == SCU0_CLK_MPHY) { -+ div = readl(reg) + 1; -+ } else if (clk_idx == SCU0_CLK_U2PHY_REFCLK) { -+ if (readl(clk_ctrl->base) & REVISION_ID) -+ div = (GET_USB_REFCLK_DIV(readl(reg)) + 1) << 4; -+ else -+ div = (GET_USB_REFCLK_DIV(readl(reg)) + 1) << 1; -+ } else { -+ return ERR_PTR(-EINVAL); -+ } ++ u32 nr_gpios; ++ struct aspeed_ltpi_gpio *gpio; ++ int rc; + -+ return devm_clk_hw_register_fixed_factor_parent_hw(clk_ctrl->dev, name, -+ parent_hw, 0, 1, div); -+} ++ gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); ++ if (!gpio) ++ return -ENOMEM; + -+static int ast2700_clk_is_enabled(struct clk_hw *hw) -+{ -+ struct clk_gate *gate = to_clk_gate(hw); -+ u32 clk = BIT(gate->bit_idx); -+ u32 reg; ++ gpio->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(gpio->base)) ++ return PTR_ERR(gpio->base); + -+ reg = readl(gate->reg); ++ gpio->dev = &pdev->dev; + -+ return !(reg & clk); -+} ++ 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 int ast2700_clk_enable(struct clk_hw *hw) -+{ -+ struct clk_gate *gate = to_clk_gate(hw); -+ u32 clk = BIT(gate->bit_idx); ++ raw_spin_lock_init(&gpio->lock); + -+ if (readl(gate->reg) & clk) -+ writel(clk, gate->reg + 0x04); ++ 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; + -+ return 0; -+} ++ aspeed_ltpi_gpio_setup_irqs(gpio, pdev); + -+static void ast2700_clk_disable(struct clk_hw *hw) -+{ -+ struct clk_gate *gate = to_clk_gate(hw); -+ u32 clk = BIT(gate->bit_idx); ++ rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); ++ if (rc < 0) ++ return rc; + -+ /* Clock is set to enable, so use write to set register */ -+ writel(clk, gate->reg); ++ return 0; +} + -+static const struct clk_ops ast2700_clk_gate_ops = { -+ .enable = ast2700_clk_enable, -+ .disable = ast2700_clk_disable, -+ .is_enabled = ast2700_clk_is_enabled, ++static struct platform_driver aspeed_ltpi_gpio_driver = { ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = aspeed_ltpi_gpio_of_table, ++ }, +}; + -+static struct clk_hw *ast2700_clk_hw_register_gate(struct device *dev, const char *name, -+ const struct clk_hw *parent_hw, -+ void __iomem *reg, u8 clock_idx, -+ unsigned long flags, spinlock_t *lock) -+{ -+ struct clk_init_data init; -+ struct clk_gate *gate; -+ struct clk_hw *hw; -+ int ret = -EINVAL; -+ -+ gate = kzalloc(sizeof(*gate), GFP_KERNEL); -+ if (!gate) -+ return ERR_PTR(-ENOMEM); -+ -+ init.name = name; -+ init.ops = &ast2700_clk_gate_ops; -+ init.flags = flags; -+ init.parent_names = NULL; -+ init.parent_hws = parent_hw ? &parent_hw : NULL; -+ init.parent_data = NULL; -+ init.num_parents = parent_hw ? 1 : 0; -+ -+ gate->reg = reg; -+ gate->bit_idx = clock_idx; -+ gate->flags = 0; -+ gate->lock = lock; -+ gate->hw.init = &init; ++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 + -+ hw = &gate->hw; -+ ret = clk_hw_register(dev, hw); -+ if (ret) { -+ kfree(gate); -+ hw = ERR_PTR(ret); -+ } ++#define BMC_CONTROL_START_INDEX 128 ++#define BMC_CONTROL_END_INDEX 143 + -+ return hw; ++static inline u32 field_get(u32 _mask, u32 _val) ++{ ++ return (((_val) & (_mask)) >> (ffs(_mask) - 1)); +} + -+static void ast2700_soc1_configure_i3c_clk(struct ast2700_clk_ctrl *clk_ctrl) ++static inline u32 field_prep(u32 _mask, u32 _val) +{ -+ if (readl(clk_ctrl->base) & REVISION_ID) { -+ u32 val; -+ -+ /* I3C 250MHz = HPLL/4 */ -+ val = readl(clk_ctrl->base + SCU1_CLK_SEL2) & ~SCU1_CLK_I3C_DIV_MASK; -+ val |= FIELD_PREP(SCU1_CLK_I3C_DIV_MASK, SCU1_CLK_I3C_DIV(4)); -+ writel(val, clk_ctrl->base + SCU1_CLK_SEL2); -+ } ++ return (((_val) << (ffs(_mask) - 1)) & (_mask)); +} + -+static inline const struct clk_hw *get_parent_hw_or_null(struct clk_hw **hws, int idx) ++static inline void ast_write_bits(void __iomem *addr, u32 mask, u32 val) +{ -+ if (idx < 0) -+ return NULL; -+ else -+ return hws[idx]; ++ iowrite32((ioread32(addr) & ~(mask)) | field_prep(mask, val), addr); +} + -+static int ast2700_soc_clk_probe(struct platform_device *pdev) ++static inline void ast_clr_bits(void __iomem *addr, u32 mask) +{ -+ const struct ast2700_clk_data *clk_data; -+ struct clk_hw_onecell_data *clk_hw_data; -+ struct ast2700_clk_ctrl *clk_ctrl; -+ struct device *dev = &pdev->dev; -+ u32 uart_clk_source = 0; -+ void __iomem *clk_base; -+ struct clk_hw **hws; -+ char *reset_name; -+ int ret; -+ int i; -+ -+ clk_ctrl = devm_kzalloc(dev, sizeof(*clk_ctrl), GFP_KERNEL); -+ if (!clk_ctrl) -+ return -ENOMEM; -+ clk_ctrl->dev = dev; -+ dev_set_drvdata(&pdev->dev, clk_ctrl); -+ -+ spin_lock_init(&clk_ctrl->lock); -+ -+ clk_base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(clk_base)) -+ return PTR_ERR(clk_base); -+ -+ clk_ctrl->base = clk_base; -+ -+ clk_data = (struct ast2700_clk_data *)device_get_match_data(dev); -+ if (!clk_data) -+ return -ENODEV; ++ 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; ++} + -+ clk_ctrl->clk_data = clk_data; -+ reset_name = devm_kasprintf(dev, GFP_KERNEL, "reset%d", clk_data->scu); + 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; + -+ clk_hw_data = devm_kzalloc(dev, struct_size(clk_hw_data, hws, clk_data->nr_clks), -+ GFP_KERNEL); -+ if (!clk_hw_data) -+ return -ENOMEM; ++ if (aspeed_sgpio_is_input(offset)) ++ return -EINVAL; + -+ clk_hw_data->num = clk_data->nr_clks; -+ hws = clk_hw_data->hws; ++ 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 (clk_data->scu) { -+ of_property_read_u32(dev->of_node, "uart-clk-source", &uart_clk_source); -+ if (uart_clk_source) { -+ u32 val = readl(clk_base + SCU1_CLK_SEL1) & ~GENMASK(12, 0); ++ if (val) ++ reg |= out_data; ++ else ++ reg &= ~out_data; + -+ uart_clk_source &= GENMASK(12, 0); -+ writel(val | uart_clk_source, clk_base + SCU1_CLK_SEL1); -+ } ++ iowrite32(reg, addr); + -+ ast2700_soc1_configure_i3c_clk(clk_ctrl); -+ } ++ return 0; ++} + -+ for (i = 0; i < clk_data->nr_clks; i++) { -+ const struct ast2700_clk_info *clk = &clk_data->clk_info[i]; -+ const struct clk_hw *phw = NULL; -+ unsigned int id = clk->id; -+ void __iomem *reg = NULL; + 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; + -+ if (id >= clk_hw_data->num || hws[id]) { -+ dev_err(dev, "clk id %u invalid for %s\n", id, clk->name); -+ return -EINVAL; -+ } ++ *offset = irqd_to_hwirq(d); ++ internal = irq_data_get_irq_chip_data(d); ++ WARN_ON(!internal); + -+ if (clk->type == CLK_FIXED) { -+ const struct ast2700_clk_fixed_rate_data *fixed_rate = &clk->data.rate; ++ *gpio = internal; ++} + -+ hws[id] = devm_clk_hw_register_fixed_rate(dev, clk->name, NULL, 0, -+ fixed_rate->fixed_rate); -+ } else if (clk->type == CLK_FIXED_FACTOR) { -+ const struct ast2700_clk_fixed_factor_data *factor = &clk->data.factor; + 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; + -+ phw = hws[factor->parent_id]; -+ hws[id] = devm_clk_hw_register_fixed_factor_parent_hw(dev, clk->name, -+ phw, 0, factor->mult, -+ factor->div); -+ } else if (clk->type == CLK_FIXED_DISPLAY) { -+ reg = clk_ctrl->base + clk->data.display_rate.reg; ++ irqd_to_aspeed_g7_sgpio_data(d, &gpio, &offset); + -+ hws[id] = ast2700_clk_hw_register_fixed_display(reg, clk->name, clk_ctrl); -+ } else if (clk->type == CLK_HPLL) { -+ const struct ast2700_clk_pll_data *pll = &clk->data.pll; ++ status_addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); + -+ reg = clk_ctrl->base + pll->reg; -+ phw = hws[pll->parent_id]; -+ hws[id] = ast2700_clk_hw_register_hpll(reg, clk->name, phw, clk_ctrl); -+ } else if (clk->type == CLK_PLL) { -+ const struct ast2700_clk_pll_data *pll = &clk->data.pll; ++ raw_spin_lock_irqsave(&gpio->lock, flags); + -+ reg = clk_ctrl->base + pll->reg; -+ phw = hws[pll->parent_id]; -+ hws[id] = ast2700_clk_hw_register_pll(id, reg, clk->name, phw, clk_ctrl); -+ } else if (clk->type == CLK_UART_PLL) { -+ const struct ast2700_clk_pll_data *pll = &clk->data.pll; ++ ast_write_bits(status_addr, SGPIO_G7_IRQ_STS, 1); + -+ reg = clk_ctrl->base + pll->reg; -+ phw = hws[pll->parent_id]; -+ hws[id] = ast2700_clk_hw_register_uartpll(reg, clk->name, phw, clk_ctrl); -+ } else if (clk->type == CLK_MUX) { -+ const struct ast2700_clk_mux_data *mux = &clk->data.mux; ++ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++} + -+ reg = clk_ctrl->base + mux->reg; -+ for (int j = 0; j < mux->num_parents; j++) { -+ unsigned int pid = mux->parent_ids[j]; + 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; + -+ mux->parent_hws[j] = hws[pid]; -+ } ++ irqd_to_aspeed_g7_sgpio_data(d, &gpio, &offset); ++ addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); + -+ hws[id] = devm_clk_hw_register_mux_parent_hws(dev, clk->name, -+ mux->parent_hws, -+ mux->num_parents, 0, -+ reg, mux->bit_shift, -+ mux->bit_width, 0, -+ &clk_ctrl->lock); -+ } else if (clk->type == CLK_MISC) { -+ const struct ast2700_clk_pll_data *pll = &clk->data.pll; ++ /* Unmasking the IRQ */ ++ if (set) ++ gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d)); + -+ reg = clk_ctrl->base + pll->reg; -+ phw = hws[pll->parent_id]; -+ hws[id] = ast2700_clk_hw_register_misc(id, reg, clk->name, phw, clk_ctrl); -+ } else if (clk->type == CLK_DIVIDER) { -+ const struct ast2700_clk_div_data *divider = &clk->data.div; ++ 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); + -+ reg = clk_ctrl->base + divider->reg; -+ phw = hws[divider->parent_id]; -+ hws[id] = clk_hw_register_divider_table_parent_hw(dev, clk->name, -+ phw, -+ 0, reg, -+ divider->bit_shift, -+ divider->bit_width, 0, -+ divider->div_table, -+ &clk_ctrl->lock); -+ } else if (clk->type == CLK_GATE_ASPEED) { -+ const struct ast2700_clk_gate_data *gate = &clk->data.gate; ++ /* Masking the IRQ */ ++ if (!set) ++ gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(d)); ++} + -+ phw = get_parent_hw_or_null(hws, gate->parent_id); -+ reg = clk_ctrl->base + gate->reg; -+ hws[id] = ast2700_clk_hw_register_gate(dev, clk->name, phw, reg, gate->bit, -+ gate->flags, &clk_ctrl->lock); -+ } else { -+ const struct ast2700_clk_gate_data *gate = &clk->data.gate; + 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); ++} + -+ phw = get_parent_hw_or_null(hws, gate->parent_id); -+ reg = clk_ctrl->base + gate->reg; -+ hws[id] = devm_clk_hw_register_gate_parent_hw(dev, clk->name, phw, -+ gate->flags, reg, gate->bit, -+ 0, &clk_ctrl->lock); -+ } ++static void aspeed_g7_sgpio_irq_unmask(struct irq_data *d) ++{ ++ aspeed_g7_sgpio_irq_set_mask(d, true); ++} + -+ if (IS_ERR(hws[id])) -+ return PTR_ERR(hws[id]); + 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; + } + -+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_hw_data); -+ if (ret) -+ return ret; ++ raw_spin_lock_irqsave(&gpio->lock, flags); + -+ return aspeed_reset_controller_register(dev, clk_base, reset_name); -+} ++ 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); + -+static const struct ast2700_clk_data ast2700_clk0_data = { -+ .scu = 0, -+ .clk_info = ast2700_scu0_clk_info, -+ .nr_clks = ARRAY_SIZE(ast2700_scu0_clk_info), -+}; ++ raw_spin_unlock_irqrestore(&gpio->lock, flags); + -+static const struct ast2700_clk_data ast2700_clk1_data = { -+ .scu = 1, -+ .clk_info = ast2700_scu1_clk_info, -+ .nr_clks = ARRAY_SIZE(ast2700_scu1_clk_info), -+}; ++ irq_set_handler_locked(d, handler); ++ return 0; ++} + -+static const struct ast2700_clk_data ast2755_clk1_data = { -+ .scu = 2, -+ .clk_info = ast2755_scu1_clk_info, -+ .nr_clks = ARRAY_SIZE(ast2755_scu1_clk_info), -+}; + 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; + -+static const struct of_device_id ast2700_scu_match[] = { -+ { .compatible = "aspeed,ast2700-scu0", .data = &ast2700_clk0_data }, -+ { .compatible = "aspeed,ast2700-scu1", .data = &ast2700_clk1_data }, -+ { .compatible = "aspeed,ast2755-scu1", .data = &ast2755_clk1_data }, -+ { /* sentinel */ } -+}; ++ chained_irq_enter(ic, desc); + -+MODULE_DEVICE_TABLE(of, ast2700_scu_match); ++ banks = DIV_ROUND_UP(gpio->chip.ngpio >> 1, 32); ++ for (i = 0; i < banks; i++) { ++ addr = gpio->base + SGPIO_G7_IRQ_STS_OFFSET(i); + -+static struct platform_driver ast2700_scu_driver = { -+ .probe = ast2700_soc_clk_probe, -+ .driver = { -+ .name = "clk-ast2700", -+ .of_match_table = ast2700_scu_match, -+ }, -+}; ++ reg = ioread32(addr); + -+static int __init clk_ast2700_init(void) ++ 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) +{ -+ return platform_driver_register(&ast2700_scu_driver); ++ struct aspeed_sgpio *gpio; ++ int offset; ++ ++ irqd_to_aspeed_g7_sgpio_data(d, &gpio, &offset); ++ seq_printf(p, dev_name(gpio->dev)); +} -+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 2026-04-08 18:03:48.327705009 +0000 -@@ -1,26 +1,32 @@ - config CRYPTO_DEV_ASPEED -- tristate "Support for Aspeed cryptographic engine driver" -+ bool "Support for Aspeed cryptographic engine driver" - depends on ARCH_ASPEED || COMPILE_TEST - select CRYPTO_ENGINE - help -- Hash and Crypto Engine (HACE) is designed to accelerate the -- throughput of hash data digest, encryption and decryption. -+ Say Y here to get to see options for Aspeed hardware crypto devices ++ + 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, + }; -- Select y here to have support for the cryptographic driver -- available on Aspeed SoC. -+if CRYPTO_DEV_ASPEED ++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 @@ - config CRYPTO_DEV_ASPEED_DEBUG - bool "Enable Aspeed crypto debug messages" -- depends on CRYPTO_DEV_ASPEED - help - Print Aspeed crypto debugging messages if you use this - option to ask for those messages. - Avoid enabling this option for production build to - minimize driver timing. + gpio->irq = rc; -+config CRYPTO_DEV_ASPEED_HACE -+ tristate "Enable Aspeed Hash & Crypto Engine (HACE) Engine" -+ help -+ Hash and Crypto Engine (HACE) is designed to accelerate the -+ throughput of hash data digest, encryption and decryption. -+ -+ Select y here to have support for the cryptographic driver -+ available on Aspeed SoC. -+ - config CRYPTO_DEV_ASPEED_HACE_HASH - bool "Enable Aspeed Hash & Crypto Engine (HACE) hash" -- depends on CRYPTO_DEV_ASPEED -+ depends on CRYPTO_DEV_ASPEED_HACE - select CRYPTO_SHA1 - select CRYPTO_SHA256 - select CRYPTO_SHA512 -@@ -33,25 +39,56 @@ +- /* 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)); ++ } - config CRYPTO_DEV_ASPEED_HACE_CRYPTO - bool "Enable Aspeed Hash & Crypto Engine (HACE) crypto" -- depends on CRYPTO_DEV_ASPEED -+ depends on CRYPTO_DEV_ASPEED_HACE - select CRYPTO_AES - select CRYPTO_DES - select CRYPTO_ECB - select CRYPTO_CBC -+ select CRYPTO_CFB -+ select CRYPTO_OFB - select CRYPTO_CTR - help - Select here to enable Aspeed Hash & Crypto Engine (HACE) - crypto driver. - Supports AES/DES symmetric-key encryption and decryption -- with ECB/CBC/CTR options. -+ with ECB/CBC/CFB/OFB/CTR options. + 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; - config CRYPTO_DEV_ASPEED_ACRY -- bool "Enable Aspeed ACRY RSA Engine" -- depends on CRYPTO_DEV_ASPEED -- select CRYPTO_ENGINE -+ tristate "Enable Aspeed ACRY RSA Engine" -+ depends on MACH_ASPEED_G6 - select CRYPTO_RSA - help - Select here to enable Aspeed ECC/RSA Engine (ACRY) - RSA driver. - Supports 256 bits to 4096 bits RSA encryption/decryption - and signature/verification. +- /* 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; + -+config CRYPTO_DEV_ASPEED_RSSS -+ tristate "Enable Aspeed RSSS Engine" -+ depends on ARCH_ASPEED -+ select CRYPTO_RSA -+ select CRYPTO_SHA3 -+ select CRYPTO_SM3 -+ select CRYPTO_SM4 -+ help -+ Select here to enable Aspeed RSSS Engine driver. -+ Supports RSA 512 to 4096 bits encryption/decryption and -+ signature/verification, SHA3-224/256/384/512 and XOF of -+ SHAKE 128/256, SM3 Hash crypto, SM4 ECB/CBC/CFB/OFB/CTR -+ cryptographic algorithms. -+ It's a new hardware design from ast2700 for simply SRAM -+ layout. ++ reg = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); + -+config CRYPTO_DEV_ASPEED_ECDSA -+ tristate "Enable Aspeed ECDSA Engine" -+ depends on ARCH_ASPEED -+ select CRYPTO_ECC -+ select CRYPTO_ECDSA -+ select CRYPTO_AKCIPHER -+ help -+ Select here to enable Aspeed ECC Engine for ECDSA driver. -+ Supports ECDSA (Elliptic Curve Digital Signature Algorithm) -+ using curves P-256, P-384. -+ Only signature verification is implemented. ++ raw_spin_lock_irqsave(&gpio->lock, flags); + -+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 2026-04-08 18:03:48.327705009 +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 - --obj-$(CONFIG_CRYPTO_DEV_ASPEED) += aspeed_crypto.o -+obj-$(CONFIG_CRYPTO_DEV_ASPEED_HACE) += aspeed_crypto.o - aspeed_crypto-objs := aspeed-hace.o \ - $(hace-hash-y) \ - $(hace-crypto-y) ++ 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); ++ } --aspeed_acry-$(CONFIG_CRYPTO_DEV_ASPEED_ACRY) += aspeed-acry.o -+obj-$(CONFIG_CRYPTO_DEV_ASPEED_ACRY) += aspeed-acry.o + return -ENOTSUPP; + } --obj-$(CONFIG_CRYPTO_DEV_ASPEED) += $(aspeed_acry-y) -+obj-$(CONFIG_CRYPTO_DEV_ASPEED_RSSS) += aspeed_rsss.o -+aspeed_rsss-objs := aspeed-rsss.o aspeed-rsss-rsa.o aspeed-rsss-hash.o + static const struct aspeed_sgpio_pdata ast2600_sgpiom_pdata = { + .pin_mask = GENMASK(10, 6), ++ .ctrl_reg = 0x54, ++}; + -+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 2026-04-08 18:03:48.327705009 +0000 -@@ -808,7 +808,7 @@ ++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, + }; - static struct platform_driver aspeed_acry_driver = { - .probe = aspeed_acry_probe, -- .remove_new = aspeed_acry_remove, -+ .remove = aspeed_acry_remove, - .driver = { - .name = KBUILD_MODNAME, - .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 2026-04-08 18:03:48.327705009 +0000 -@@ -0,0 +1,779 @@ -+// 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 -+#include -+#include -+ -+#include "aspeed-ecdsa.h" -+ -+//#define ASPEED_ECDSA_IRQ_MODE + 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); ++ } + -+static int aspeed_ecdsa_self_test(struct aspeed_ecdsa_dev *ecdsa_dev) -+{ -+ u32 val; ++ 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; ++ } + -+ ast_write(ecdsa_dev, ECC_EN, ASPEED_ECC_CTRL_REG); -+ val = ast_read(ecdsa_dev, ASPEED_ECC_CTRL_REG); -+ if (val != ECC_EN) -+ return -EIO; ++ 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); ++ } + -+ ast_write(ecdsa_dev, 0x0, ASPEED_ECC_CTRL_REG); -+ val = ast_read(ecdsa_dev, ASPEED_ECC_CTRL_REG); -+ if (val) -+ return -EIO; ++ apb_freq = clk_get_rate(gpio->pclk); + -+ return 0; -+} ++ /* ++ * 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; + -+static inline struct akcipher_request * -+ akcipher_request_cast(struct crypto_async_request *req) -+{ -+ return container_of(req, struct akcipher_request, base); -+} ++ sgpio_clk_div = (apb_freq / (sgpio_freq * 2)) - 1; + -+#ifdef CONFIG_CRYPTO_DEV_ASPEED_DEBUG -+static void hexdump(const char *name, unsigned char *buf, unsigned int len) -+{ -+ pr_info("%s\n", name); -+ print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET, -+ 16, 1, -+ buf, len, false); -+} -+#else -+static void hexdump(const char *name, unsigned char *buf, unsigned int len) -+{ -+ /* empty */ -+} -+#endif ++ if (sgpio_clk_div > (1 << 16) - 1) ++ return -EINVAL; + -+static void buff_reverse(u8 *dst, u8 *src, int len) -+{ -+ for (int i = 0; i < len; i++) -+ dst[len - i - 1] = src[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 + 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)) + -+static bool aspeed_ecdsa_need_fallback(struct aspeed_ecc_ctx *ctx, int d_len) -+{ -+ int curve_id = ctx->curve_id; ++#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) + -+ switch (curve_id) { -+ case ECC_CURVE_NIST_P256: -+ if (d_len != SHA256_DIGEST_SIZE) -+ return true; -+ break; -+ case ECC_CURVE_NIST_P384: -+ if (d_len != SHA384_DIGEST_SIZE) -+ return true; -+ break; -+ } + 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 }; + -+ return false; -+} ++/* ++ * 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); ++}; + -+#ifndef ASPEED_ECDSA_IRQ_MODE -+static int aspeed_ecdsa_wait_complete(struct aspeed_ecdsa_dev *ecdsa_dev) + #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) +{ -+ struct aspeed_engine_ecdsa *ecdsa_engine = &ecdsa_dev->ecdsa_engine; -+ u32 sts; -+ int ret; -+ -+ ret = readl_poll_timeout(ecdsa_dev->regs + ASPEED_ECC_STS_REG, sts, -+ ((sts & ECC_IDLE) == ECC_IDLE), -+ ASPEED_ECC_POLLING_TIME, -+ ASPEED_ECC_TIMEOUT * 10); -+ if (ret) { -+ dev_err(ecdsa_dev->dev, "ECC engine wrong status\n"); -+ return -EIO; -+ } -+ -+ sts = ast_read(ecdsa_dev, ASPEED_ECC_STS_REG) & ECC_VERIFY_PASS; -+ if (sts == ECC_VERIFY_PASS) { -+ ecdsa_engine->results = 0; -+ AST_DBG(ecdsa_dev, "Verify PASS !\n"); -+ -+ } else { -+ ecdsa_engine->results = -EKEYREJECTED; -+ AST_DBG(ecdsa_dev, "Verify FAILED !\n"); ++ 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; + } -+ -+ /* Stop ECDSA engine */ -+ if (ecdsa_engine->flags & CRYPTO_FLAGS_BUSY) -+ tasklet_schedule(&ecdsa_engine->done_task); -+ else -+ dev_err(ecdsa_dev->dev, "ECDSA no active requests.\n"); -+ -+ return ecdsa_engine->results; +} -+#endif + -+static int aspeed_hw_trigger(struct aspeed_ecdsa_dev *ecdsa_dev) -+{ -+ AST_DBG(ecdsa_dev, "\n"); -+ -+ ast_write(ecdsa_dev, 0x1, ASPEED_ECC_ECDSA_VERIFY); -+ -+ ast_write(ecdsa_dev, ECC_EN, ASPEED_ECC_CMD_REG); -+ ast_write(ecdsa_dev, 0x0, ASPEED_ECC_CMD_REG); -+ -+#ifdef ASPEED_ECDSA_IRQ_MODE -+ return 0; -+#else -+ return aspeed_ecdsa_wait_complete(ecdsa_dev); -+#endif -+} + #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; + -+static int _aspeed_ecdsa_verify(struct aspeed_ecc_ctx *ctx, const u64 *hash, -+ const u64 *r, const u64 *s) ++ 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) +{ -+ int nbytes = ctx->curve->g.ndigits << ECC_DIGITS_TO_BYTES_SHIFT; -+ const struct ecc_curve *curve = ctx->curve; -+ void __iomem *base = ctx->ecdsa_dev->regs; -+ unsigned int ndigits = curve->g.ndigits; -+ u8 *data, *buf; -+ -+ /* 0 < r < n and 0 < s < n */ -+ if (vli_is_zero(r, ndigits) || vli_cmp(r, curve->n, ndigits) >= 0 || -+ vli_is_zero(s, ndigits) || vli_cmp(s, curve->n, ndigits) >= 0) -+ return -EBADMSG; -+ -+ /* hash is given */ -+ AST_DBG(ctx->ecdsa_dev, "hash : %016llx %016llx ... %016llx\n", -+ hash[ndigits - 1], hash[ndigits - 2], hash[0]); -+ -+ data = vmalloc(nbytes); -+ if (!data) -+ return -ENOMEM; -+ -+ /* Initial signature/message and trigger ecdsa verification */ -+ buf = (u8 *)r; -+ hexdump("Dump r:", buf, nbytes); -+ -+ buff_reverse(data, (u8 *)r, nbytes); -+ memcpy_toio(base + ASPEED_ECC_SIGN_R_REG, data, nbytes); -+ -+ buf = (u8 *)s; -+ hexdump("Dump s:", buf, nbytes); -+ -+ buff_reverse(data, (u8 *)s, nbytes); -+ memcpy_toio(base + ASPEED_ECC_SIGN_S_REG, data, nbytes); -+ -+ buf = (u8 *)hash; -+ hexdump("Dump m:", buf, nbytes); -+ -+ buff_reverse(data, (u8 *)hash, nbytes); -+ memcpy_toio(base + ASPEED_ECC_MESSAGE_REG, data, nbytes); -+ -+ vfree(data); -+ -+ return aspeed_hw_trigger(ctx->ecdsa_dev); ++ 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); +} -+ -+static int aspeed_ecdsa_handle_queue(struct aspeed_ecdsa_dev *ecdsa_dev, -+ struct akcipher_request *req) + +- /* Restart the coprocessor */ +- copro_ops->release_access(copro_data); ++static bool aspeed_gpio_support_copro(struct aspeed_gpio *gpio) +{ -+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); -+ struct aspeed_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); -+ int ret; -+ -+ if (aspeed_ecdsa_need_fallback(ctx, req->dst_len)) { -+ AST_DBG(ctx->ecdsa_dev, "SW fallback\n"); ++ 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 @@ + + 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; + -+ akcipher_request_set_tfm(req, ctx->fallback_tfm); -+ ret = crypto_akcipher_verify(req); -+ akcipher_request_set_tfm(req, tfm); + 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; + -+ AST_DBG(ctx->ecdsa_dev, "SW verify...ret:0x%x\n", ret); + 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; + -+ return ret; -+ } ++ if (reg == reg_val) ++ temp = gpio->dcache[GPIO_BANK(offset)]; ++ else ++ temp = ioread32(addr); + -+ return crypto_transfer_akcipher_request_to_engine(ecdsa_dev->crypt_engine_ecdsa, req); -+} -+ -+static int aspeed_ecdsa_trigger(struct aspeed_ecdsa_dev *ecdsa_dev) -+{ -+ struct aspeed_engine_ecdsa *ecdsa_engine = &ecdsa_dev->ecdsa_engine; -+ struct akcipher_request *req = ecdsa_engine->req; -+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); -+ struct aspeed_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); -+ size_t keylen = ctx->curve->g.ndigits * sizeof(u64); -+ struct ecdsa_signature_ctx sig_ctx = { -+ .curve = ctx->curve, -+ }; -+ u8 rawhash[ECC_MAX_BYTES]; -+ u64 hash[ECC_MAX_DIGITS]; -+ unsigned char *buffer; -+ ssize_t diff; -+ int ret; -+ -+ AST_DBG(ecdsa_dev, "\n"); -+ -+ if (unlikely(!ctx->pub_key_set)) -+ return -EINVAL; -+ -+ buffer = kmalloc(req->src_len + req->dst_len, GFP_KERNEL); -+ if (!buffer) -+ return -ENOMEM; -+ -+ /* Input src: signature + digest */ -+ sg_pcopy_to_buffer(req->src, sg_nents_for_len(req->src, req->src_len + req->dst_len), -+ buffer, req->src_len + req->dst_len, 0); -+ -+ ret = asn1_ber_decoder(&ecdsasignature_decoder, &sig_ctx, -+ buffer, req->src_len); -+ if (ret < 0) -+ goto error; -+ -+ /* if the hash is shorter then we will add leading zeros to fit to ndigits */ -+ diff = keylen - req->dst_len; -+ if (diff >= 0) { -+ if (diff) -+ memset(rawhash, 0, diff); -+ memcpy(&rawhash[diff], buffer + req->src_len, req->dst_len); -+ } else if (diff < 0) { -+ /* given hash is longer, we take the left-most bytes */ -+ memcpy(&rawhash, buffer + req->src_len, keylen); -+ } -+ -+ ecc_swap_digits((u64 *)rawhash, hash, ctx->curve->g.ndigits); -+ -+ ret = _aspeed_ecdsa_verify(ctx, hash, sig_ctx.r, sig_ctx.s); -+ -+error: -+ kfree(buffer); -+ -+ return ret; -+} -+ -+/* -+ * Verify an ECDSA signature. -+ */ -+static int aspeed_ecdsa_verify(struct akcipher_request *req) -+{ -+ struct crypto_akcipher *cipher = crypto_akcipher_reqtfm(req); -+ struct aspeed_ecc_ctx *ctx = akcipher_tfm_ctx(cipher); -+ struct aspeed_ecdsa_dev *ecdsa_dev = ctx->ecdsa_dev; -+ -+ AST_DBG(ecdsa_dev, "\n"); -+ -+ ctx->trigger = aspeed_ecdsa_trigger; -+ -+ return aspeed_ecdsa_handle_queue(ecdsa_dev, req); -+} -+ -+static int aspeed_ecdsa_ecc_ctx_init(struct aspeed_ecc_ctx *ctx, unsigned int curve_id) -+{ -+ void __iomem *base = ctx->ecdsa_dev->regs; -+ u8 *data, *buf; -+ u32 ctrl; -+ int nbytes; -+ -+ ctx->curve_id = curve_id; -+ ctx->curve = ecc_get_curve(curve_id); -+ if (!ctx->curve) -+ return -EINVAL; -+ -+ nbytes = ctx->curve->g.ndigits << ECC_DIGITS_TO_BYTES_SHIFT; -+ -+ switch (curve_id) { -+ case ECC_CURVE_NIST_P256: -+ AST_DBG(ctx->ecdsa_dev, "curve ECC_CURVE_NIST_P256\n"); -+ ctrl = ECDSA_256_EN; -+ break; -+ case ECC_CURVE_NIST_P384: -+ AST_DBG(ctx->ecdsa_dev, "curve ECC_CURVE_NIST_P384\n"); -+ ctrl = ECDSA_384_EN; -+ break; -+ } -+ -+ mutex_lock(&ctx->ecdsa_dev->lock); -+ -+ ast_write(ctx->ecdsa_dev, ECC_EN | ctrl, ASPEED_ECC_CTRL_REG); -+ -+ /* Initial Curve: ecc point/p/a/n */ -+ data = vmalloc(nbytes); -+ if (!data) -+ return -ENOMEM; -+ -+ buf = (u8 *)ctx->curve->g.x; -+ hexdump("Dump Gx:", buf, nbytes); -+ -+ buff_reverse(data, (u8 *)ctx->curve->g.x, nbytes); -+ memcpy_toio(base + ASPEED_ECC_PAR_GX_REG, data, nbytes); -+ -+ buf = (u8 *)ctx->curve->g.y; -+ hexdump("Dump Gy:", buf, nbytes); -+ -+ buff_reverse(data, (u8 *)ctx->curve->g.y, nbytes); -+ memcpy_toio(base + ASPEED_ECC_PAR_GY_REG, data, nbytes); -+ -+ buf = (u8 *)ctx->curve->p; -+ hexdump("Dump P:", buf, nbytes); -+ -+ buff_reverse(data, (u8 *)ctx->curve->p, nbytes); -+ memcpy_toio(base + ASPEED_ECC_PAR_P_REG, data, nbytes); -+ -+ buf = (u8 *)ctx->curve->a; -+ hexdump("Dump A:", buf, nbytes); -+ -+ buff_reverse(data, (u8 *)ctx->curve->a, nbytes); -+ memcpy_toio(base + ASPEED_ECC_PAR_A_REG, data, nbytes); -+ -+ buf = (u8 *)ctx->curve->n; -+ hexdump("Dump N:", buf, nbytes); -+ -+ buff_reverse(data, (u8 *)ctx->curve->n, nbytes); -+ memcpy_toio(base + ASPEED_ECC_PAR_N_REG, data, nbytes); -+ -+ vfree(data); -+ return 0; -+} -+ -+static void aspeed_ecdsa_ecc_ctx_deinit(struct aspeed_ecc_ctx *ctx) -+{ -+ mutex_unlock(&ctx->ecdsa_dev->lock); -+ -+ ctx->pub_key_set = false; -+} ++ if (val) ++ temp |= GPIO_BIT(offset); ++ else ++ temp &= ~GPIO_BIT(offset); + -+static void aspeed_ecdsa_ecc_ctx_reset(struct aspeed_ecc_ctx *ctx) -+{ -+ ctx->pub_key = ECC_POINT_INIT(ctx->x, ctx->y, -+ ctx->curve->g.ndigits); ++ if (reg == reg_val) ++ gpio->dcache[GPIO_BANK(offset)] = temp; ++ iowrite32(temp, addr); +} + -+/* -+ * Set the public key given the raw uncompressed key data from an X509 -+ * certificate. The key data contain the concatenated X and Y coordinates of -+ * the public key. -+ */ -+static int aspeed_ecdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, -+ unsigned int keylen) ++static bool aspeed_g4_reg_bit_get(struct aspeed_gpio *gpio, unsigned int offset, ++ const enum aspeed_gpio_reg reg) +{ -+ struct aspeed_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); -+ int nbytes = ctx->curve->g.ndigits << ECC_DIGITS_TO_BYTES_SHIFT; -+ void __iomem *base = ctx->ecdsa_dev->regs; -+ const unsigned char *d = key; -+ const u64 *digits = (const u64 *)&d[1]; -+ unsigned int ndigits; -+ u8 *data, *buf; -+ int ret; -+ -+ AST_DBG(ctx->ecdsa_dev, "\n"); -+ -+ ret = crypto_akcipher_set_pub_key(ctx->fallback_tfm, key, keylen); -+ if (ret) -+ return ret; -+ -+ aspeed_ecdsa_ecc_ctx_reset(ctx); -+ -+ if (keylen < 1 || (((keylen - 1) >> 1) % sizeof(u64)) != 0) -+ return -EINVAL; -+ /* we only accept uncompressed format indicated by '4' */ -+ if (d[0] != 4) -+ return -EINVAL; -+ -+ keylen--; -+ ndigits = (keylen >> 1) / sizeof(u64); -+ if (ndigits != ctx->curve->g.ndigits) -+ return -EINVAL; -+ -+ ecc_swap_digits(digits, ctx->pub_key.x, ndigits); -+ ecc_swap_digits(&digits[ndigits], ctx->pub_key.y, ndigits); -+ ret = ecc_is_pubkey_valid_full(ctx->curve, &ctx->pub_key); -+ -+ /* Set public key: Qx/Qy */ -+ data = vmalloc(nbytes); -+ if (!data) -+ return -ENOMEM; -+ -+ buf = (u8 *)ctx->pub_key.x; -+ hexdump("Dump Qx:", buf, nbytes); -+ -+ buff_reverse(data, (u8 *)ctx->pub_key.x, nbytes); -+ memcpy_toio(base + ASPEED_ECC_PAR_QX_REG, data, nbytes); -+ -+ buf = (u8 *)ctx->pub_key.y; -+ hexdump("Dump Qy:", buf, nbytes); -+ -+ buff_reverse(data, (u8 *)ctx->pub_key.y, nbytes); -+ memcpy_toio(base + ASPEED_ECC_PAR_QY_REG, data, nbytes); -+ -+ ctx->pub_key_set = ret == 0; -+ -+ vfree(data); ++ const struct aspeed_gpio_bank *bank = to_bank(offset); ++ void __iomem *addr = aspeed_gpio_g4_bank_reg(gpio, bank, reg); + -+ return ret; ++ return !!(ioread32(addr) & GPIO_BIT(offset)); +} + -+static void aspeed_ecdsa_exit_tfm(struct crypto_akcipher *tfm) ++static int aspeed_g4_reg_bank_get(struct aspeed_gpio *gpio, unsigned int offset, ++ const enum aspeed_gpio_reg reg) +{ -+ struct aspeed_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); -+ -+ AST_DBG(ctx->ecdsa_dev, "\n"); -+ -+ aspeed_ecdsa_ecc_ctx_deinit(ctx); ++ const struct aspeed_gpio_bank *bank = to_bank(offset); ++ void __iomem *addr = aspeed_gpio_g4_bank_reg(gpio, bank, reg); + -+ crypto_free_akcipher(ctx->fallback_tfm); ++ if (reg == reg_rdata || reg == reg_irq_status) ++ return ioread32(addr); ++ else ++ return -EOPNOTSUPP; +} + -+static unsigned int aspeed_ecdsa_max_size(struct crypto_akcipher *tfm) ++static void aspeed_g4_privilege_ctrl(struct aspeed_gpio *gpio, unsigned int offset, int cmdsrc) +{ -+ struct aspeed_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); -+ -+ return ctx->pub_key.ndigits << ECC_DIGITS_TO_BYTES_SHIFT; ++ /* ++ * 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))); +} + -+static int aspeed_ecdsa_nist_p384_init_tfm(struct crypto_akcipher *tfm) ++static void aspeed_g4_privilege_init(struct aspeed_gpio *gpio) +{ -+ struct aspeed_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); -+ struct akcipher_alg *alg = crypto_akcipher_alg(tfm); -+ const char *name = crypto_tfm_alg_name(&tfm->base); -+ struct aspeed_ecdsa_alg *ecdsa_alg; -+ -+ ecdsa_alg = container_of(alg, struct aspeed_ecdsa_alg, akcipher.base); -+ -+ ctx->ecdsa_dev = ecdsa_alg->ecdsa_dev; ++ u32 i; + -+ AST_DBG(ctx->ecdsa_dev, "\n"); -+ ctx->fallback_tfm = crypto_alloc_akcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK); -+ if (IS_ERR(ctx->fallback_tfm)) { -+ dev_err(ctx->ecdsa_dev->dev, "ERROR: Cannot allocate fallback for %s %ld\n", -+ name, PTR_ERR(ctx->fallback_tfm)); -+ return PTR_ERR(ctx->fallback_tfm); ++ /* 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); + } -+ -+ return aspeed_ecdsa_ecc_ctx_init(ctx, ECC_CURVE_NIST_P384); +} + -+static int aspeed_ecdsa_nist_p256_init_tfm(struct crypto_akcipher *tfm) ++static bool aspeed_g4_copro_request(struct aspeed_gpio *gpio, unsigned int offset) +{ -+ struct aspeed_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); -+ struct akcipher_alg *alg = crypto_akcipher_alg(tfm); -+ const char *name = crypto_tfm_alg_name(&tfm->base); -+ struct aspeed_ecdsa_alg *ecdsa_alg; ++ 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; + -+ ecdsa_alg = container_of(alg, struct aspeed_ecdsa_alg, akcipher.base); ++ /* Pause the coprocessor */ ++ copro_ops->request_access(copro_data); + -+ ctx->ecdsa_dev = ecdsa_alg->ecdsa_dev; ++ /* Change command source back to ARM */ ++ aspeed_g4_privilege_ctrl(gpio, offset, GPIO_CMDSRC_ARM); + -+ AST_DBG(ctx->ecdsa_dev, "\n"); -+ ctx->fallback_tfm = crypto_alloc_akcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK); -+ if (IS_ERR(ctx->fallback_tfm)) { -+ dev_err(ctx->ecdsa_dev->dev, "ERROR: Cannot allocate fallback for %s %ld\n", -+ name, PTR_ERR(ctx->fallback_tfm)); -+ return PTR_ERR(ctx->fallback_tfm); -+ } ++ /* Update cache */ ++ gpio->dcache[GPIO_BANK(offset)] = aspeed_g4_reg_bank_get(gpio, offset, reg_rdata); + -+ return aspeed_ecdsa_ecc_ctx_init(ctx, ECC_CURVE_NIST_P256); ++ return true; +} + -+static int aspeed_ecdsa_complete(struct aspeed_ecdsa_dev *ecdsa_dev) ++static void aspeed_g4_copro_release(struct aspeed_gpio *gpio, unsigned int offset) +{ -+ struct aspeed_engine_ecdsa *ecdsa_engine = &ecdsa_dev->ecdsa_engine; -+ struct akcipher_request *req = ecdsa_engine->req; -+ int results = ecdsa_engine->results; -+ -+ AST_DBG(ecdsa_dev, "\n"); -+ -+ ecdsa_engine->flags &= ~CRYPTO_FLAGS_BUSY; ++ if (!copro_ops || !gpio->cf_copro_bankmap) ++ return; ++ if (!gpio->cf_copro_bankmap[offset >> 3]) ++ return; ++ if (!copro_ops->release_access) ++ return; + -+ crypto_finalize_akcipher_request(ecdsa_dev->crypt_engine_ecdsa, req, results); ++ /* Change command source back to ColdFire */ ++ aspeed_g4_privilege_ctrl(gpio, offset, GPIO_CMDSRC_COLDFIRE); + -+ return results; ++ /* Restart the coprocessor */ ++ copro_ops->release_access(copro_data); +} + -+static int aspeed_ecdsa_do_request(struct crypto_engine *engine, void *areq) -+{ -+ struct akcipher_request *req = akcipher_request_cast(areq); -+ struct crypto_akcipher *cipher = crypto_akcipher_reqtfm(req); -+ struct aspeed_ecc_ctx *ctx = akcipher_tfm_ctx(cipher); -+ struct aspeed_ecdsa_dev *ecdsa_dev = ctx->ecdsa_dev; -+ struct aspeed_engine_ecdsa *ecdsa_engine; -+ -+ AST_DBG(ctx->ecdsa_dev, "\n"); -+ -+ ecdsa_engine = &ecdsa_dev->ecdsa_engine; -+ ecdsa_engine->req = req; -+ ecdsa_engine->flags |= CRYPTO_FLAGS_BUSY; -+ ecdsa_engine->resume = aspeed_ecdsa_complete; -+ -+ return ctx->trigger(ecdsa_dev); -+} ++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 void aspeed_ecdsa_done_task(unsigned long data) ++static void aspeed_g7_reg_bit_set(struct aspeed_gpio *gpio, unsigned int offset, ++ const enum aspeed_gpio_reg reg, bool val) +{ -+ struct aspeed_ecdsa_dev *ecdsa_dev = (struct aspeed_ecdsa_dev *)data; -+ struct aspeed_engine_ecdsa *ecdsa_engine = &ecdsa_dev->ecdsa_engine; -+ u32 ctrl; -+ -+ AST_DBG(ecdsa_dev, "\n"); -+ -+ /* Reset engine */ -+ ctrl = ast_read(ecdsa_dev, ASPEED_ECC_CTRL_REG); -+ ast_write(ecdsa_dev, 0, ASPEED_ECC_CTRL_REG); -+ -+ /* Memory barrier to ensure ecc ctrl is reset. */ -+ mb(); -+ ast_write(ecdsa_dev, ctrl, ASPEED_ECC_CTRL_REG); ++ u32 mask = aspeed_gpio_g7_reg_mask(reg); ++ void __iomem *addr = gpio->base + GPIO_G7_CTRL_REG_OFFSET(offset); ++ u32 write_val; + -+ (void)ecdsa_engine->resume(ecdsa_dev); ++ if (mask) { ++ write_val = (ioread32(addr) & ~(mask)) | field_prep(mask, val); ++ iowrite32(write_val, addr); ++ } +} + -+static struct aspeed_ecdsa_alg aspeed_ecdsa_nist_p256 = { -+ .akcipher.base = { -+ .verify = aspeed_ecdsa_verify, -+ .set_pub_key = aspeed_ecdsa_set_pub_key, -+ .max_size = aspeed_ecdsa_max_size, -+ .init = aspeed_ecdsa_nist_p256_init_tfm, -+ .exit = aspeed_ecdsa_exit_tfm, -+ .base = { -+ .cra_name = "ecdsa-nist-p256", -+ .cra_driver_name = "aspeed-ecdsa-nist-p256", -+ .cra_priority = 300, -+ .cra_module = THIS_MODULE, -+ .cra_ctxsize = sizeof(struct aspeed_ecc_ctx), -+ .cra_flags = CRYPTO_ALG_TYPE_AKCIPHER | -+ CRYPTO_ALG_KERN_DRIVER_ONLY | -+ CRYPTO_ALG_NEED_FALLBACK, -+ }, -+ }, -+ .akcipher.op = { -+ .do_one_request = aspeed_ecdsa_do_request, -+ }, -+}; -+ -+static struct aspeed_ecdsa_alg aspeed_ecdsa_nist_p384 = { -+ .akcipher.base = { -+ .verify = aspeed_ecdsa_verify, -+ .set_pub_key = aspeed_ecdsa_set_pub_key, -+ .max_size = aspeed_ecdsa_max_size, -+ .init = aspeed_ecdsa_nist_p384_init_tfm, -+ .exit = aspeed_ecdsa_exit_tfm, -+ .base = { -+ .cra_name = "ecdsa-nist-p384", -+ .cra_driver_name = "aspeed-ecdsa-nist-p384", -+ .cra_priority = 300, -+ .cra_module = THIS_MODULE, -+ .cra_ctxsize = sizeof(struct aspeed_ecc_ctx), -+ .cra_flags = CRYPTO_ALG_TYPE_AKCIPHER | -+ CRYPTO_ALG_KERN_DRIVER_ONLY | -+ CRYPTO_ALG_NEED_FALLBACK, -+ }, -+ }, -+ .akcipher.op = { -+ .do_one_request = aspeed_ecdsa_do_request, -+ }, -+}; -+ -+static int aspeed_ecdsa_register(struct aspeed_ecdsa_dev *ecdsa_dev) ++static bool aspeed_g7_reg_bit_get(struct aspeed_gpio *gpio, unsigned int offset, ++ const enum aspeed_gpio_reg reg) +{ -+ int rc; -+ -+ aspeed_ecdsa_nist_p256.ecdsa_dev = ecdsa_dev; -+ rc = crypto_engine_register_akcipher(&aspeed_ecdsa_nist_p256.akcipher); -+ if (rc) -+ goto nist_p256_error; -+ -+ aspeed_ecdsa_nist_p384.ecdsa_dev = ecdsa_dev; -+ rc = crypto_engine_register_akcipher(&aspeed_ecdsa_nist_p384.akcipher); -+ if (rc) -+ goto nist_p384_error; -+ -+ return 0; -+ -+nist_p384_error: -+ crypto_engine_unregister_akcipher(&aspeed_ecdsa_nist_p256.akcipher); ++ u32 mask = aspeed_gpio_g7_reg_mask(reg); ++ void __iomem *addr; + -+nist_p256_error: -+ return rc; -+} ++ addr = gpio->base + GPIO_G7_CTRL_REG_OFFSET(offset); ++ if (reg == reg_val) ++ mask = GPIO_G7_CTRL_IN_DATA; + -+static void aspeed_ecdsa_unregister(struct aspeed_ecdsa_dev *ecdsa_dev) -+{ -+ crypto_engine_unregister_akcipher(&aspeed_ecdsa_nist_p256.akcipher); -+ crypto_engine_unregister_akcipher(&aspeed_ecdsa_nist_p384.akcipher); ++ if (mask) ++ return field_get(mask, ioread32(addr)); ++ else ++ return 0; +} + -+#ifdef ASPEED_ECDSA_IRQ_MODE -+/* ecdsa interrupt service routine. */ -+static irqreturn_t aspeed_ecdsa_irq(int irq, void *dev) ++static int aspeed_g7_reg_bank_get(struct aspeed_gpio *gpio, unsigned int offset, ++ const enum aspeed_gpio_reg reg) +{ -+ struct aspeed_ecdsa_dev *ecdsa_dev = (struct aspeed_ecdsa_dev *)dev; -+ struct aspeed_engine_ecdsa *ecdsa_engine = &ecdsa_dev->ecdsa_engine; -+ u32 sts; -+ -+ sts = ast_read(ecdsa_dev, ASPEED_ECC_INT_STS); -+ ast_write(ecdsa_dev, sts, ASPEED_ECC_INT_STS); -+ -+ AST_DBG(ecdsa_dev, "irq sts:0x%x\n", sts); -+ -+ sts = ast_read(ecdsa_dev, ASPEED_ECC_STS_REG) & ECC_VERIFY_PASS; -+ if (sts == ECC_VERIFY_PASS) { -+ AST_DBG(ecdsa_dev, "Verify PASS !\n"); -+ -+ ecdsa_engine->results = 0; -+ /* Stop ECDSA engine */ -+ if (ecdsa_engine->flags & CRYPTO_FLAGS_BUSY) -+ tasklet_schedule(&ecdsa_engine->done_task); -+ else -+ dev_err(ecdsa_dev->dev, "ECDSA no active requests.\n"); ++ void __iomem *addr; + ++ if (reg == reg_irq_status) { ++ addr = gpio->base + GPIO_G7_IRQ_STS_OFFSET(offset >> 5); ++ return ioread32(addr); + } else { -+ ecdsa_engine->results = -EKEYREJECTED; -+ AST_DBG(ecdsa_dev, "Verify FAILED !\n"); ++ return -EOPNOTSUPP; + } -+ -+ return IRQ_HANDLED; +} -+#endif + -+static const struct of_device_id aspeed_ecdsa_of_matches[] = { -+ { .compatible = "aspeed,ast2700-ecdsa", }, -+ {}, ++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 int aspeed_ecdsa_probe(struct platform_device *pdev) -+{ -+ struct aspeed_engine_ecdsa *ecdsa_engine; -+ struct aspeed_ecdsa_dev *ecdsa_dev; -+ struct device *dev = &pdev->dev; -+ int rc; -+ -+ ecdsa_dev = devm_kzalloc(dev, sizeof(struct aspeed_ecdsa_dev), -+ GFP_KERNEL); -+ if (!ecdsa_dev) -+ return -ENOMEM; -+ -+ ecdsa_dev->dev = dev; -+ -+ platform_set_drvdata(pdev, ecdsa_dev); -+ -+ ecdsa_dev->regs = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(ecdsa_dev->regs)) -+ return PTR_ERR(ecdsa_dev->regs); + /* + * 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, ++ }; + -+#ifdef ASPEED_ECDSA_IRQ_MODE -+ /* Get irq number and register it */ -+ ecdsa_dev->irq = platform_get_irq(pdev, 0); -+ if (ecdsa_dev->irq < 0) -+ return -ENXIO; ++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 */ ++ {}, ++}; + -+ rc = devm_request_irq(dev, ecdsa_dev->irq, aspeed_ecdsa_irq, 0, -+ dev_name(dev), ecdsa_dev); -+ if (rc) { -+ dev_err(dev, "Failed to request irq.\n"); -+ return rc; -+ } ++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; + -+ /* Enable interrupt */ -+ ast_write(ecdsa_dev, 0x1, ASPEED_ECC_INT_EN); -+#endif + 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); + -+ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); -+ if (rc) { -+ dev_warn(&pdev->dev, "No suitable DMA available\n"); -+ return rc; -+ } + /* 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 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; + -+ ecdsa_dev->clk = devm_clk_get_enabled(dev, NULL); -+ if (IS_ERR(ecdsa_dev->clk)) { -+ dev_err(dev, "Failed to get ecdsa clk\n"); -+ return PTR_ERR(ecdsa_dev->clk); -+ } ++ 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; +@@ -106,3 +123,58 @@ + /* CRT_THROD */ + #define CRT_THROD_LOW(x) (x) + #define CRT_THROD_HIGH(x) ((x) << 8) + -+ ecdsa_dev->rst = devm_reset_control_get_shared(dev, NULL); -+ if (IS_ERR(ecdsa_dev->rst)) { -+ dev_err(dev, "Failed to get ecdsa reset\n"); -+ return PTR_ERR(ecdsa_dev->rst); -+ } ++/* 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) + -+ rc = reset_control_deassert(ecdsa_dev->rst); -+ if (rc) { -+ dev_err(dev, "Deassert ecdsa reset failed\n"); -+ return rc; -+ } ++/* 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) + -+ ecdsa_engine = &ecdsa_dev->ecdsa_engine; ++/* 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) + -+ /* Initialize crypto hardware engine structure for ECDSA */ -+ ecdsa_dev->crypt_engine_ecdsa = crypto_engine_alloc_init(ecdsa_dev->dev, true); -+ if (!ecdsa_dev->crypt_engine_ecdsa) { -+ rc = -ENOMEM; -+ goto end; -+ } ++/* 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) + -+ rc = crypto_engine_start(ecdsa_dev->crypt_engine_ecdsa); -+ if (rc) -+ goto err_engine_ecdsa_start; ++/* 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 */ + -+ tasklet_init(&ecdsa_engine->done_task, aspeed_ecdsa_done_task, -+ (unsigned long)ecdsa_dev); ++/* 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); + } + ++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); ++} + -+ /* Self-test */ -+ rc = aspeed_ecdsa_self_test(ecdsa_dev); -+ if (rc) -+ goto err_engine_ecdsa_start; ++static void aspeed_gfx_set_g6_clock_source(struct aspeed_gfx *priv, int mode_width) ++{ ++ 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); + -+ rc = aspeed_ecdsa_register(ecdsa_dev); -+ if (rc) { -+ dev_err(dev, "ECDSA algo register failed\n"); -+ return rc; ++ 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; + } -+ -+ mutex_init(&ecdsa_dev->lock); -+ -+ dev_info(dev, "Aspeed ECDSA Hardware Accelerator successfully registered\n"); -+ -+ return 0; -+ -+err_engine_ecdsa_start: -+ crypto_engine_exit(ecdsa_dev->crypt_engine_ecdsa); -+end: -+ return rc; +} + -+static void aspeed_ecdsa_remove(struct platform_device *pdev) ++static void aspeed_gfx_set_g7_clock(struct aspeed_gfx *priv) +{ -+ struct aspeed_ecdsa_dev *ecdsa_dev = platform_get_drvdata(pdev); -+ -+ aspeed_ecdsa_unregister(ecdsa_dev); ++ /* apply 800 x 600 @ 62 on ast2700 */ ++ regmap_update_bits(priv->scu, 0x288, BIT(14), BIT(14)); ++ regmap_write(priv->scu, 0x340, 0x00130002); +} + -+MODULE_DEVICE_TABLE(of, aspeed_ecdsa_of_matches); -+ -+static struct platform_driver aspeed_ecdsa_driver = { -+ .probe = aspeed_ecdsa_probe, -+ .remove = aspeed_ecdsa_remove, -+ .driver = { -+ .name = KBUILD_MODNAME, -+ .of_match_table = aspeed_ecdsa_of_matches, -+ }, -+}; -+ -+module_platform_driver(aspeed_ecdsa_driver); -+MODULE_AUTHOR("Neal Liu "); -+MODULE_DESCRIPTION("ASPEED ECDSA algorithm driver acceleration"); -+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 2026-04-08 18:03:48.327705009 +0000 -@@ -0,0 +1,119 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+ -+#ifndef __ASPEED_ECDSA_H__ -+#define __ASPEED_ECDSA_H__ + static int aspeed_gfx_set_pixel_fmt(struct aspeed_gfx *priv, u32 *bpp) + { + 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); + +- /* 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); ++ } + + 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); + +- 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); ++} + -+#ifdef CONFIG_CRYPTO_DEV_ASPEED_DEBUG -+#define AST_DBG(d, fmt, ...) \ -+ dev_info((d)->dev, "%s() " fmt, __func__, ##__VA_ARGS__) -+#else -+#define AST_DBG(d, fmt, ...) \ -+ dev_dbg((d)->dev, "%s() " fmt, __func__, ##__VA_ARGS__) -+#endif ++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; ++ } ++} + -+/************************* -+ * * -+ * ECDSA regs definition * -+ * * -+ *************************/ -+#define ASPEED_ECC_STS_REG 0xb0 -+#define ASPEED_ECC_CTRL_REG 0xb4 -+#define ASPEED_ECC_CMD_REG 0xbc -+#define ASPEED_ECC_INT_EN 0xc0 -+#define ASPEED_ECC_INT_STS 0xc4 ++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; ++ } + } + + static void aspeed_gfx_crtc_mode_set_nofb(struct aspeed_gfx *priv) +@@ -87,6 +160,8 @@ + if (err) + return; + ++ aspeed_gfx_set_clk(priv, m->hdisplay); + -+#define ASPEED_ECC_DATA_BASE 0x800 -+#define ASPEED_ECC_PAR_GX_REG 0x800 -+#define ASPEED_ECC_PAR_GY_REG 0x840 -+#define ASPEED_ECC_PAR_QX_REG 0x880 -+#define ASPEED_ECC_PAR_QY_REG 0x8c0 -+#define ASPEED_ECC_PAR_P_REG 0x900 -+#define ASPEED_ECC_PAR_A_REG 0x940 -+#define ASPEED_ECC_PAR_N_REG 0x980 -+#define ASPEED_ECC_SIGN_R_REG 0x9c0 -+#define ASPEED_ECC_SIGN_S_REG 0xa00 -+#define ASPEED_ECC_MESSAGE_REG 0xa40 -+#define ASPEED_ECC_ECDSA_VERIFY 0xbc0 + #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); + -+/* sts */ -+#define ECC_IDLE BIT(0) -+#define ECC_VERIFY_PASS BIT(1) ++ /* 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 +266,17 @@ + gem = drm_fb_dma_get_gem_obj(fb, 0); + if (!gem) + return; +- writel(gem->dma_addr, priv->base + CRT_ADDR); + -+/* ctrl/cmd */ -+#define ECC_EN BIT(0) -+#define ECDSA_384_EN 0x0 -+#define ECDSA_256_EN BIT(1) -+#define ADDR_BE BIT(2) -+#define DATA_BE BIT(3) ++ 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); + -+#define PAR_LEN_256 32 -+#define PAR_LEN_384 48 + u32 reg = readl(priv->base + CRT_CTRL1); + + /* Clear pending VBLANK IRQ */ +@@ -207,6 +291,7 @@ + static void aspeed_gfx_disable_vblank(struct drm_simple_display_pipe *pipe) + { + struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe); + -+#define ASPEED_ECC_POLLING_TIME 100 -+#define ASPEED_ECC_TIMEOUT 100000 /* 100 ms */ -+ -+#define CRYPTO_FLAGS_BUSY BIT(1) -+ -+#define ast_write(ast, val, offset) \ -+ writel((val), (ast)->regs + (offset)) -+ -+#define ast_read(ast, offset) \ -+ readl((ast)->regs + (offset)) -+ -+struct aspeed_ecdsa_dev; -+ -+typedef int (*aspeed_ecdsa_fn_t)(struct aspeed_ecdsa_dev *); -+ -+struct aspeed_ecc_ctx { -+ struct aspeed_ecdsa_dev *ecdsa_dev; -+ unsigned int curve_id; -+ const struct ecc_curve *curve; -+ -+ bool pub_key_set; -+ u64 x[ECC_MAX_DIGITS]; /* pub key x and y coordinates */ -+ u64 y[ECC_MAX_DIGITS]; -+ struct ecc_point pub_key; -+ -+ struct crypto_akcipher *fallback_tfm; -+ -+ aspeed_ecdsa_fn_t trigger; -+}; -+ -+struct ecdsa_signature_ctx { -+ const struct ecc_curve *curve; -+ u64 r[ECC_MAX_DIGITS]; -+ u64 s[ECC_MAX_DIGITS]; -+}; -+ -+struct aspeed_engine_ecdsa { -+ struct tasklet_struct done_task; -+ unsigned long flags; -+ struct akcipher_request *req; -+ int results; -+ -+ /* callback func */ -+ aspeed_ecdsa_fn_t resume; -+}; -+ -+struct aspeed_ecdsa_alg { -+ struct aspeed_ecdsa_dev *ecdsa_dev; -+ struct akcipher_engine_alg akcipher; -+}; -+ -+struct aspeed_ecdsa_dev { -+ void __iomem *regs; -+ struct device *dev; -+ struct clk *clk; -+ struct reset_control *rst; -+ int irq; -+ -+ /* Support ecdsa256/384 execution concurrent */ -+ struct mutex lock; -+ -+ struct crypto_engine *crypt_engine_ecdsa; -+ struct aspeed_engine_ecdsa ecdsa_engine; -+}; -+ -+extern const struct asn1_decoder ecdsasignature_decoder; -+ -+#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 2026-04-08 18:03:48.327705009 +0000 -@@ -24,6 +24,11 @@ - dev_dbg((h)->dev, "%s() " fmt, __func__, ##__VA_ARGS__) - #endif + u32 reg = readl(priv->base + CRT_CTRL1); -+#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_crypto_do_fallback(struct skcipher_request *areq) - { - struct aspeed_cipher_reqctx *rctx = skcipher_request_ctx(areq); -@@ -143,6 +148,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); - } -+ up(&hace_dev->lock); + 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*/ + }; - return aspeed_sk_complete(hace_dev, 0); - } -@@ -206,10 +212,21 @@ - crypto_engine->resume = aspeed_sk_transfer; + 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, + }; - /* Trigger engines */ -+ ast_hace_write(hace_dev, crypto_engine->cipher_ctx_dma, -+ ASPEED_HACE_CONTEXT); - ast_hace_write(hace_dev, crypto_engine->cipher_dma_addr, - ASPEED_HACE_SRC); - ast_hace_write(hace_dev, crypto_engine->cipher_dma_addr, - ASPEED_HACE_DEST); -+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT -+ 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->cipher_dma_addr >> 32, -+ ASPEED_HACE_DEST_H); -+#endif -+ - ast_hace_write(hace_dev, req->cryptlen, ASPEED_HACE_DATA_LEN); - ast_hace_write(hace_dev, rctx->enc_cmd, ASPEED_HACE_CMD); + 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, + }; -@@ -222,21 +239,65 @@ - struct aspeed_sg_list *src_list, *dst_list; - dma_addr_t src_dma_addr, dst_dma_addr; - struct aspeed_cipher_reqctx *rctx; -+ struct crypto_skcipher *cipher; -+ 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; + 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), + }; - CIPHER_DBG(hace_dev, "\n"); + 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 @@ - req = crypto_engine->req; -+ cipher = crypto_skcipher_reqtfm(req); -+ ctx = crypto_skcipher_ctx(cipher); - rctx = skcipher_request_ctx(req); + static int aspeed_gfx_setup_mode_config(struct drm_device *drm) + { ++ struct aspeed_gfx *priv = to_aspeed_gfx(drm); + int ret; - 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; + ret = drmm_mode_config_init(drm); +@@ -113,13 +168,63 @@ -+ 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)); + drm->mode_config.min_width = 0; + drm->mode_config.min_height = 0; +- drm->mode_config.max_width = 800; +- drm->mode_config.max_height = 600; + -+ if (use_vault_key) -+ rctx->enc_cmd |= HACE_CMD_AES_KEY_FROM_OTP; -+ else -+ rctx->enc_cmd &= ~HACE_CMD_AES_KEY_FROM_OTP; ++ 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; + } + - /* BIDIRECTIONAL */ - if (req->dst == req->src) { - src_sg_len = dma_map_sg(hace_dev->dev, req->src, -@@ -332,8 +393,19 @@ - mb(); - - /* Trigger engines */ -+ down(&hace_dev->lock); -+ ast_hace_write(hace_dev, crypto_engine->cipher_ctx_dma, -+ ASPEED_HACE_CONTEXT); - ast_hace_write(hace_dev, src_dma_addr, ASPEED_HACE_SRC); - ast_hace_write(hace_dev, dst_dma_addr, ASPEED_HACE_DEST); -+ -+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT -+ ast_hace_write(hace_dev, crypto_engine->cipher_ctx_dma >> 32, -+ ASPEED_HACE_CONTEXT_H); -+ ast_hace_write(hace_dev, src_dma_addr >> 32, ASPEED_HACE_SRC_H); -+ ast_hace_write(hace_dev, dst_dma_addr >> 32, ASPEED_HACE_DEST_H); -+#endif -+ - 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 @@ - rctx->dst_nents = sg_nents(req->dst); - rctx->src_nents = sg_nents(req->src); - -- ast_hace_write(hace_dev, crypto_engine->cipher_ctx_dma, -- ASPEED_HACE_CONTEXT); -- - 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 @@ - AES_BLOCK_SIZE); - } - -- if (hace_dev->version == AST2600_VERSION) { -+ if (hace_dev->version == AST2600_VERSION || -+ hace_dev->version == AST2700_VERSION) { - memcpy(crypto_engine->cipher_ctx + 16, ctx->key, ctx->key_len); - - return aspeed_sk_start_sg(hace_dev); -@@ -580,6 +650,8 @@ - - CIPHER_DBG(hace_dev, "keylen: %d bits\n", (keylen * 8)); - -+ ctx->dummy_key = find_dummy_key(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); - -- if (hace_dev->version != AST2600_VERSION) -+ if (hace_dev->version == AST2500_VERSION) - return; + drm->mode_config.funcs = &aspeed_gfx_mode_config_funcs; - for (i = 0; i < ARRAY_SIZE(aspeed_crypto_algs_g6); i++) - crypto_engine_unregister_skcipher(&aspeed_crypto_algs_g6[i].alg.skcipher); + return ret; } -+#ifdef CONFIG_AST2600_OTP -+static void find_vault_key(struct aspeed_hace_dev *hace_dev) ++static irqreturn_t aspeed_host_irq_handler(int irq, void *data) +{ -+ struct aspeed_engine_crypto *crypto_engine = &hace_dev->crypto_engine; -+ u32 otp_data[16]; -+ int i; ++ struct drm_device *drm = data; ++ struct aspeed_gfx *priv = to_aspeed_gfx(drm); ++ u32 reg; + -+ crypto_engine->load_vault_key = 0; ++ regmap_read(priv->scu, priv->pcie_int_reg, ®); + -+ 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 (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); ++ } ++ ++ /*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); ++ } ++ ++ /*Change the CRT into soc*/ ++ regmap_update_bits(priv->scu, priv->dac_reg, priv->soc_crt_bit, priv->soc_crt_bit); + } -+ if (otp_data[i] & BIT(13)) -+ break; ++ return IRQ_HANDLED; + } -+ CIPHER_DBG(hace_dev, "Not found vault key in OTP\n"); ++ ++ return IRQ_NONE; +} -+#endif + - void aspeed_register_hace_crypto_algs(struct aspeed_hace_dev *hace_dev) + static irqreturn_t aspeed_gfx_irq_handler(int irq, void *data) { - int rc, i; - - CIPHER_DBG(hace_dev, "\n"); + struct drm_device *drm = data; +@@ -137,6 +242,145 @@ + return IRQ_NONE; + } -+#ifdef CONFIG_AST2600_OTP -+ find_vault_key(hace_dev); -+#else -+ hace_dev->crypto_engine.load_vault_key = 0; -+#endif ++static int aspeed_pcie_active_detect(struct drm_device *drm) ++{ ++ struct aspeed_gfx *priv = to_aspeed_gfx(drm); ++ u32 reg = 0; + - 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 @@ - } - } - -- if (hace_dev->version != AST2600_VERSION) -+ if (hace_dev->version == AST2500_VERSION) - return; - - for (i = 0; i < ARRAY_SIZE(aspeed_crypto_algs_g6); i++) { -@@ -953,3 +1055,88 @@ - } - } - } ++ /* 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); ++ } ++ } ++ } + -+static void aspeed_hace_crypto_done_task(unsigned long data) -+{ -+ struct aspeed_hace_dev *hace_dev = (struct aspeed_hace_dev *)data; -+ struct aspeed_engine_crypto *crypto_engine = &hace_dev->crypto_engine; ++ /* check pcie rst status */ ++ regmap_read(priv->pcie_ep, priv->pcie_link_reg, ®); + -+ crypto_engine->resume(hace_dev); ++ /* 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; +} + -+int aspeed_hace_crypto_init(struct aspeed_hace_dev *hace_dev) ++static int aspeed_adaptor_detect(struct drm_device *drm) +{ -+ struct aspeed_engine_crypto *crypto_engine; -+ int rc; ++ struct aspeed_gfx *priv = to_aspeed_gfx(drm); ++ u32 dp_status_offset = 0, reg = 0; + -+ crypto_engine = &hace_dev->crypto_engine; ++ 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; + -+ /* Initialize crypto hardware engine structure for crypto */ -+ hace_dev->crypt_engine_crypto = crypto_engine_alloc_init(hace_dev->dev, -+ true); -+ if (!hace_dev->crypt_engine_crypto) { -+ rc = -ENOMEM; -+ goto end; -+ } ++ 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); ++ } + -+ rc = crypto_engine_start(hace_dev->crypt_engine_crypto); -+ if (rc) -+ goto err_engine_crypto_start; ++ 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); ++ } + -+ tasklet_init(&crypto_engine->done_task, aspeed_hace_crypto_done_task, -+ (unsigned long)hace_dev); ++ /* 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); ++ } ++ break; ++ case CLK_G7: ++ /* check AST DP is located on PCIE0 or PCIE1 */ ++ regmap_read(priv->scu, priv->dac_reg, ®); + -+ /* Allocate DMA buffer for crypto engine context used */ -+ crypto_engine->cipher_ctx = -+ dmam_alloc_coherent(hace_dev->dev, -+ PAGE_SIZE, -+ &crypto_engine->cipher_ctx_dma, -+ GFP_KERNEL); -+ if (!crypto_engine->cipher_ctx) { -+ dev_err(hace_dev->dev, "Failed to allocate cipher ctx dma\n"); -+ rc = -ENOMEM; -+ goto err_engine_crypto_start; -+ } ++ if (reg & DP_LOCATE_PCIE1) ++ dp_status_offset = SCU_PCIE1_DP_STATUS; ++ else ++ dp_status_offset = SCU_PCIE0_DP_STATUS; + -+ /* Allocate DMA buffer for crypto engine input used */ -+ crypto_engine->cipher_addr = -+ dmam_alloc_coherent(hace_dev->dev, -+ ASPEED_CRYPTO_SRC_DMA_BUF_LEN, -+ &crypto_engine->cipher_dma_addr, -+ GFP_KERNEL); -+ if (!crypto_engine->cipher_addr) { -+ dev_err(hace_dev->dev, "Failed to allocate cipher addr dma\n"); -+ rc = -ENOMEM; -+ goto err_engine_crypto_start; -+ } ++ /* 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; + -+ /* Allocate DMA buffer for crypto engine output used */ -+ if (hace_dev->version == AST2600_VERSION || -+ hace_dev->version == AST2700_VERSION) { -+ crypto_engine->dst_sg_addr = -+ dmam_alloc_coherent(hace_dev->dev, -+ ASPEED_CRYPTO_DST_DMA_BUF_LEN, -+ &crypto_engine->dst_sg_dma_addr, -+ GFP_KERNEL); -+ if (!crypto_engine->dst_sg_addr) { -+ dev_err(hace_dev->dev, "Failed to allocate dst_sg dma\n"); -+ rc = -ENOMEM; -+ goto err_engine_crypto_start; ++ 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); ++ } ++ ++ 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); ++ } ++ ++ /* change the dp setting is coming from soc display */ ++ regmap_update_bits(priv->dp, DP_SOURCE, DP_CONTROL_FROM_SOC, DP_CONTROL_FROM_SOC); + } -+ } + ++ break; ++ default: ++ priv->dp_support = 0x0; ++ priv->dp = NULL; ++ priv->dpmcu = NULL; ++ break; ++ } + return 0; -+ -+err_engine_crypto_start: -+ crypto_engine_exit(hace_dev->crypt_engine_crypto); -+end: -+ return rc; +} + -+void aspeed_hace_crypto_remove(struct aspeed_hace_dev *hace_dev) ++static int aspeed_gfx_reset(struct drm_device *drm) +{ -+ struct aspeed_engine_crypto *crypto_engine = &hace_dev->crypto_engine; ++ struct platform_device *pdev = to_platform_device(drm->dev); ++ struct aspeed_gfx *priv = to_aspeed_gfx(drm); + -+ crypto_engine_exit(hace_dev->crypt_engine_crypto); -+ tasklet_kill(&crypto_engine->done_task); ++ 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); ++ ++ 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; ++ ++ 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; ++ } ++ ++ return 0; +} -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 2026-04-08 18:03:48.327705009 +0000 -@@ -138,21 +138,13 @@ - return -EINVAL; - } - -- scatterwalk_map_and_copy(rctx->buffer, rctx->src_sg, -- rctx->offset, remain, 0); -+ scatterwalk_map_and_copy(rctx->buffer, rctx->src_sg, rctx->offset, -+ remain, 0); - - rctx->bufcnt = remain; -- rctx->digest_dma_addr = dma_map_single(hace_dev->dev, rctx->digest, -- SHA512_DIGEST_SIZE, -- DMA_BIDIRECTIONAL); -- if (dma_mapping_error(hace_dev->dev, rctx->digest_dma_addr)) { -- dev_warn(hace_dev->dev, "dma_map() rctx digest error\n"); -- return -ENOMEM; -- } ++ + static int aspeed_gfx_load(struct drm_device *drm) + { + 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; - hash_engine->src_length = length - remain; - hash_engine->src_dma = hash_engine->ahash_src_dma_addr; -- hash_engine->digest_dma = rctx->digest_dma_addr; + 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 0; - } -@@ -187,30 +179,12 @@ + 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); ++ } ++ } + } } - src_list = (struct aspeed_sg_list *)hash_engine->ahash_src_addr; -- rctx->digest_dma_addr = dma_map_single(hace_dev->dev, rctx->digest, -- SHA512_DIGEST_SIZE, -- DMA_BIDIRECTIONAL); -- if (dma_mapping_error(hace_dev->dev, rctx->digest_dma_addr)) { -- dev_warn(hace_dev->dev, "dma_map() rctx digest error\n"); -- rc = -ENOMEM; -- goto free_src_sg; -- } +@@ -177,19 +449,18 @@ + return ret; + } - if (rctx->bufcnt != 0) { - u32 phy_addr; - u32 len; +- 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; + } -- rctx->buffer_dma_addr = dma_map_single(hace_dev->dev, -- rctx->buffer, -- rctx->block_size * 2, -- DMA_TO_DEVICE); -- if (dma_mapping_error(hace_dev->dev, rctx->buffer_dma_addr)) { -- dev_warn(hace_dev->dev, "dma_map() rctx buffer error\n"); -- rc = -ENOMEM; -- goto free_rctx_digest; -- } -- -- phy_addr = rctx->buffer_dma_addr; -+ phy_addr = hash_engine->buffer_dma_addr; - len = rctx->bufcnt; - length -= len; +- 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); -@@ -244,23 +218,15 @@ + priv->clk = devm_clk_get(drm->dev, NULL); + if (IS_ERR(priv->clk)) { +@@ -199,6 +470,22 @@ + } + clk_prepare_enable(priv->clk); - if (length != 0) { - rc = -EINVAL; -- goto free_rctx_buffer; -+ goto free_src_sg; ++ 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; } - rctx->offset = rctx->total - remain; - hash_engine->src_length = rctx->total + rctx->bufcnt - remain; - hash_engine->src_dma = hash_engine->ahash_src_dma_addr; -- hash_engine->digest_dma = rctx->digest_dma_addr; ++ /* 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); return 0; +@@ -239,6 +543,12 @@ --free_rctx_buffer: -- if (rctx->bufcnt != 0) -- dma_unmap_single(hace_dev->dev, rctx->buffer_dma_addr, -- rctx->block_size * 2, DMA_TO_DEVICE); --free_rctx_digest: -- dma_unmap_single(hace_dev->dev, rctx->digest_dma_addr, -- SHA512_DIGEST_SIZE, DMA_BIDIRECTIONAL); - free_src_sg: - dma_unmap_sg(hace_dev->dev, rctx->src_sg, rctx->src_nents, - DMA_TO_DEVICE); -@@ -294,13 +260,15 @@ - - AHASH_DBG(hace_dev, "\n"); - -- dma_unmap_single(hace_dev->dev, rctx->digest_dma_addr, -- SHA512_DIGEST_SIZE, DMA_BIDIRECTIONAL); -- -- dma_unmap_single(hace_dev->dev, rctx->buffer_dma_addr, -- rctx->block_size * 2, DMA_TO_DEVICE); -+ memcpy(req->result, hash_engine->digest_addr, rctx->digsize); - -- memcpy(req->result, rctx->digest, rctx->digsize); -+ /* -+ * Workaround for aes engine hang: The sha configuration may cause aes -+ * engine to hang. To address this issue, the hace engine is reset after -+ * the hash calculation is completed. -+ */ -+ aspeed_hace_reset(hace_dev); -+ up(&hace_dev->lock); - - return aspeed_ahash_complete(hace_dev); - } -@@ -315,13 +283,18 @@ - struct ahash_request *req = hash_engine->req; - struct aspeed_sham_reqctx *rctx = ahash_request_ctx(req); - -+ memcpy(hash_engine->digest_addr, rctx->digest, rctx->ivsize); -+ memcpy(hash_engine->buffer_addr, rctx->buffer, rctx->bufcnt); -+ hash_engine->digest_dma = hash_engine->digest_dma_addr; + static void aspeed_gfx_unload(struct drm_device *drm) + { ++ struct aspeed_gfx *priv = drm->dev_private; + - AHASH_DBG(hace_dev, "src_dma:%pad, digest_dma:%pad, length:%zu\n", - &hash_engine->src_dma, &hash_engine->digest_dma, - hash_engine->src_length); - -- rctx->cmd |= HASH_CMD_INT_ENABLE; -+ rctx->cmd |= HASH_CMD_INT_ENABLE | HASH_CMD_MBUS_REQ_SYNC_EN; - hash_engine->resume = resume; - -+ /* Trigger engines */ - ast_hace_write(hace_dev, hash_engine->src_dma, ASPEED_HACE_HASH_SRC); - ast_hace_write(hace_dev, hash_engine->digest_dma, - ASPEED_HACE_HASH_DIGEST_BUFF); -@@ -329,6 +302,14 @@ - ASPEED_HACE_HASH_KEY_BUFF); - ast_hace_write(hace_dev, hash_engine->src_length, - ASPEED_HACE_HASH_DATA_LEN); -+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT -+ ast_hace_write(hace_dev, hash_engine->src_dma >> 32, -+ ASPEED_HACE_HASH_SRC_H); -+ ast_hace_write(hace_dev, hash_engine->digest_dma >> 32, -+ ASPEED_HACE_HASH_DIGEST_BUFF_H); -+ ast_hace_write(hace_dev, hash_engine->digest_dma >> 32, -+ ASPEED_HACE_HASH_KEY_BUFF_H); -+#endif - - /* Memory barrier to ensure all data setup before engine starts */ - mb(); -@@ -351,15 +332,10 @@ - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct aspeed_sham_ctx *tctx = crypto_ahash_ctx(tfm); - struct aspeed_sha_hmac_ctx *bctx = tctx->base; -- int rc = 0; - - AHASH_DBG(hace_dev, "\n"); - -- dma_unmap_single(hace_dev->dev, rctx->digest_dma_addr, -- SHA512_DIGEST_SIZE, DMA_BIDIRECTIONAL); -- -- dma_unmap_single(hace_dev->dev, rctx->buffer_dma_addr, -- rctx->block_size * 2, DMA_TO_DEVICE); -+ memcpy(rctx->digest, hash_engine->digest_addr, rctx->ivsize); - - /* o key pad + hash sum 1 */ - memcpy(rctx->buffer, bctx->opad, rctx->block_size); -@@ -371,35 +347,10 @@ - aspeed_ahash_fill_padding(hace_dev, rctx); - memcpy(rctx->digest, rctx->sha_iv, rctx->ivsize); - -- rctx->digest_dma_addr = dma_map_single(hace_dev->dev, rctx->digest, -- SHA512_DIGEST_SIZE, -- DMA_BIDIRECTIONAL); -- if (dma_mapping_error(hace_dev->dev, rctx->digest_dma_addr)) { -- dev_warn(hace_dev->dev, "dma_map() rctx digest error\n"); -- rc = -ENOMEM; -- goto end; -- } -- -- rctx->buffer_dma_addr = dma_map_single(hace_dev->dev, rctx->buffer, -- rctx->block_size * 2, -- DMA_TO_DEVICE); -- if (dma_mapping_error(hace_dev->dev, rctx->buffer_dma_addr)) { -- dev_warn(hace_dev->dev, "dma_map() rctx buffer error\n"); -- rc = -ENOMEM; -- goto free_rctx_digest; -- } -- -- hash_engine->src_dma = rctx->buffer_dma_addr; -+ hash_engine->src_dma = hash_engine->buffer_dma_addr; - hash_engine->src_length = rctx->bufcnt; -- hash_engine->digest_dma = rctx->digest_dma_addr; - - return aspeed_hace_ahash_trigger(hace_dev, aspeed_ahash_transfer); -- --free_rctx_digest: -- dma_unmap_single(hace_dev->dev, rctx->digest_dma_addr, -- SHA512_DIGEST_SIZE, DMA_BIDIRECTIONAL); --end: -- return rc; - } - - static int aspeed_ahash_req_final(struct aspeed_hace_dev *hace_dev) -@@ -407,47 +358,19 @@ - struct aspeed_engine_hash *hash_engine = &hace_dev->hash_engine; - struct ahash_request *req = hash_engine->req; - struct aspeed_sham_reqctx *rctx = ahash_request_ctx(req); -- int rc = 0; - - AHASH_DBG(hace_dev, "\n"); - - aspeed_ahash_fill_padding(hace_dev, rctx); - -- rctx->digest_dma_addr = dma_map_single(hace_dev->dev, -- rctx->digest, -- SHA512_DIGEST_SIZE, -- DMA_BIDIRECTIONAL); -- if (dma_mapping_error(hace_dev->dev, rctx->digest_dma_addr)) { -- dev_warn(hace_dev->dev, "dma_map() rctx digest error\n"); -- rc = -ENOMEM; -- goto end; -- } -- -- rctx->buffer_dma_addr = dma_map_single(hace_dev->dev, -- rctx->buffer, -- rctx->block_size * 2, -- DMA_TO_DEVICE); -- if (dma_mapping_error(hace_dev->dev, rctx->buffer_dma_addr)) { -- dev_warn(hace_dev->dev, "dma_map() rctx buffer error\n"); -- rc = -ENOMEM; -- goto free_rctx_digest; -- } -- -- hash_engine->src_dma = rctx->buffer_dma_addr; -+ hash_engine->src_dma = hash_engine->buffer_dma_addr; - hash_engine->src_length = rctx->bufcnt; -- hash_engine->digest_dma = rctx->digest_dma_addr; - - if (rctx->flags & SHA_FLAGS_HMAC) - return aspeed_hace_ahash_trigger(hace_dev, - aspeed_ahash_hmac_resume); - - return aspeed_hace_ahash_trigger(hace_dev, aspeed_ahash_transfer); -- --free_rctx_digest: -- dma_unmap_single(hace_dev->dev, rctx->digest_dma_addr, -- SHA512_DIGEST_SIZE, DMA_BIDIRECTIONAL); --end: -- return rc; - } - - static int aspeed_ahash_update_resume_sg(struct aspeed_hace_dev *hace_dev) -@@ -458,17 +381,11 @@ - - AHASH_DBG(hace_dev, "\n"); - -+ memcpy(rctx->digest, hash_engine->digest_addr, rctx->ivsize); ++ /* 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); + - dma_unmap_sg(hace_dev->dev, rctx->src_sg, rctx->src_nents, - DMA_TO_DEVICE); - -- if (rctx->bufcnt != 0) -- dma_unmap_single(hace_dev->dev, rctx->buffer_dma_addr, -- rctx->block_size * 2, -- DMA_TO_DEVICE); -- -- dma_unmap_single(hace_dev->dev, rctx->digest_dma_addr, -- SHA512_DIGEST_SIZE, DMA_BIDIRECTIONAL); -- - scatterwalk_map_and_copy(rctx->buffer, rctx->src_sg, rctx->offset, - rctx->total - rctx->offset, 0); - -@@ -489,8 +406,7 @@ - - AHASH_DBG(hace_dev, "\n"); - -- dma_unmap_single(hace_dev->dev, rctx->digest_dma_addr, -- SHA512_DIGEST_SIZE, DMA_BIDIRECTIONAL); -+ memcpy(rctx->digest, hash_engine->digest_addr, rctx->ivsize); - - if (rctx->flags & SHA_FLAGS_FINUP) - return aspeed_ahash_req_final(hace_dev); -@@ -508,12 +424,12 @@ - - AHASH_DBG(hace_dev, "\n"); - -- if (hace_dev->version == AST2600_VERSION) { -- rctx->cmd |= HASH_CMD_HASH_SRC_SG_CTRL; -- resume = aspeed_ahash_update_resume_sg; -+ if (hace_dev->version == AST2500_VERSION) { -+ resume = aspeed_ahash_update_resume; + drm_kms_helper_poll_fini(drm); + } - } else { -- resume = aspeed_ahash_update_resume; -+ rctx->cmd |= HASH_CMD_HASH_SRC_SG_CTRL; -+ resume = aspeed_ahash_update_resume_sg; - } +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 @@ - ret = hash_engine->dma_prepare(hace_dev); -@@ -526,8 +442,32 @@ - static int aspeed_hace_hash_handle_queue(struct aspeed_hace_dev *hace_dev, - struct ahash_request *req) + static int aspeed_gfx_get_modes(struct drm_connector *connector) { -- return crypto_transfer_hash_request_to_engine( -- hace_dev->crypt_engine_hash, req); -+ struct aspeed_sham_reqctx *rctx = ahash_request_ctx(req); -+ struct aspeed_engine_hash *hash_engine = &hace_dev->hash_engine; -+ int ret = 0; -+ static bool init_req; +- return drm_add_modes_noedid(connector, 800, 600); ++ struct aspeed_gfx *priv = container_of(connector, struct aspeed_gfx, connector); ++ int mode_count = 0; + -+ /* The first request is enqueued, lock the queue */ -+ if (rctx->op & SHA_OP_INIT) { -+ mutex_lock(&hash_engine->queue_lock); -+ init_req = true; -+ return 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; + } + -+ /* The previous request is init request, enqueue the request with init flag */ -+ if (init_req) { -+ rctx->op |= SHA_OP_INIT; -+ init_req = false; -+ } -+ -+ ret = crypto_transfer_hash_request_to_engine(hace_dev->crypt_engine_hash, -+ req); -+ -+ /* The last request is enqueued, release the lock */ -+ if (rctx->op & SHA_OP_FINAL || rctx->flags & SHA_FLAGS_FINUP) -+ mutex_unlock(&hash_engine->queue_lock); -+ -+ return ret; ++ return mode_count; } - static int aspeed_ahash_do_request(struct crypto_engine *engine, void *areq) -@@ -543,9 +483,14 @@ - hash_engine = &hace_dev->hash_engine; - hash_engine->flags |= CRYPTO_FLAGS_BUSY; + 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. -- if (rctx->op == SHA_OP_UPDATE) -+ /* If the update/final is the first request, lock hace engine */ -+ if (rctx->op & SHA_OP_INIT) -+ down(&hace_dev->lock); ++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. + -+ /* Do the update/final operation no matter what */ -+ if (rctx->op & SHA_OP_UPDATE) - ret = aspeed_ahash_req_update(hace_dev); -- else if (rctx->op == SHA_OP_FINAL) -+ else if (rctx->op & SHA_OP_FINAL) - ret = aspeed_ahash_req_final(hace_dev); - - if (ret != -EINPROGRESS) -@@ -566,10 +511,10 @@ - hash_engine = &hace_dev->hash_engine; - hash_engine->req = req; - -- if (hace_dev->version == AST2600_VERSION) -- hash_engine->dma_prepare = aspeed_ahash_dma_prepare_sg; -- else -+ if (hace_dev->version == AST2500_VERSION) - hash_engine->dma_prepare = aspeed_ahash_dma_prepare; -+ else -+ hash_engine->dma_prepare = aspeed_ahash_dma_prepare_sg; - } - - static int aspeed_ahash_do_one(struct crypto_engine *engine, void *areq) -@@ -671,6 +616,7 @@ - crypto_ahash_digestsize(tfm)); - - rctx->cmd = HASH_CMD_ACC_MODE; -+ rctx->op = SHA_OP_INIT; - rctx->flags = 0; - - switch (crypto_ahash_digestsize(tfm)) { -@@ -740,7 +686,7 @@ - rctx->flags |= SHA_FLAGS_HMAC; - } - -- return 0; -+ return aspeed_hace_hash_handle_queue(hace_dev, req); - } - - static int aspeed_sham_digest(struct ahash_request *req) -@@ -1196,7 +1142,7 @@ - for (i = 0; i < ARRAY_SIZE(aspeed_ahash_algs); i++) - crypto_engine_unregister_ahash(&aspeed_ahash_algs[i].alg.ahash); - -- if (hace_dev->version != AST2600_VERSION) -+ if (hace_dev->version == AST2500_VERSION) - return; - - for (i = 0; i < ARRAY_SIZE(aspeed_ahash_algs_g6); i++) -@@ -1218,7 +1164,7 @@ - } - } - -- if (hace_dev->version != AST2600_VERSION) -+ if (hace_dev->version == AST2500_VERSION) - return; - - for (i = 0; i < ARRAY_SIZE(aspeed_ahash_algs_g6); i++) { -@@ -1230,3 +1176,82 @@ - } - } - } ++ To compile this driver as a module, choose M here: the module ++ will be called aspeed-chassis. + -+static void aspeed_hace_hash_done_task(unsigned long data) + 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) +{ -+ struct aspeed_hace_dev *hace_dev = (struct aspeed_hace_dev *)data; -+ struct aspeed_engine_hash *hash_engine = &hace_dev->hash_engine; ++ unsigned long val; ++ struct aspeed_chassis *chassis = dev_get_drvdata(dev); ++ union chassis_ctrl_register chassis_ctrl; + -+ hash_engine->resume(hace_dev); ++ 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; +} + -+int aspeed_hace_hash_init(struct aspeed_hace_dev *hace_dev) ++static ssize_t intrusion_show(struct device *dev, struct device_attribute *attr, ++ char *buf) +{ -+ struct aspeed_engine_hash *hash_engine; -+ int rc; ++ 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; + -+ hash_engine = &hace_dev->hash_engine; ++ chassis_ctrl.value = readl(chassis->base); + -+ /* Initialize crypto hardware engine structure for hash */ -+ hace_dev->crypt_engine_hash = crypto_engine_alloc_init(hace_dev->dev, -+ true); -+ if (!hace_dev->crypt_engine_hash) { -+ rc = -ENOMEM; -+ goto end; ++ 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; + } + -+ rc = crypto_engine_start(hace_dev->crypt_engine_hash); -+ if (rc) -+ goto err_engine_hash_start; ++ return sprintf(buf, "%d\n", ret); ++} + -+ tasklet_init(&hash_engine->done_task, aspeed_hace_hash_done_task, -+ (unsigned long)hace_dev); ++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); + -+ /* Allocate DMA buffer for hash engine input used */ -+ hash_engine->ahash_src_addr = -+ dmam_alloc_coherent(hace_dev->dev, -+ ASPEED_HASH_SRC_DMA_BUF_LEN, -+ &hash_engine->ahash_src_dma_addr, -+ GFP_KERNEL); -+ if (!hash_engine->ahash_src_addr) { -+ dev_err(hace_dev->dev, "Failed to allocate dma buffer\n"); -+ rc = -ENOMEM; -+ goto err_engine_hash_start; -+ } ++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 ++}; + -+ hash_engine->buffer_addr = dmam_alloc_coherent(hace_dev->dev, SHA512_BLOCK_SIZE * 2, -+ &hash_engine->buffer_dma_addr, -+ GFP_KERNEL); -+ if (!hash_engine->buffer_addr) { -+ dev_err(hace_dev->dev, "Failed to allocate DMA buffer\n"); -+ rc = -ENOMEM; -+ goto err_engine_hash_start; -+ } ++static const struct attribute_group intrusion_dev_group = { ++ .attrs = intrusion_dev_attrs, ++ .is_visible = NULL, ++}; + -+ hash_engine->digest_addr = dmam_alloc_coherent(hace_dev->dev, SHA512_DIGEST_SIZE, -+ &hash_engine->digest_dma_addr, -+ GFP_KERNEL); -+ if (!hash_engine->digest_addr) { -+ dev_err(hace_dev->dev, "Failed to allocate DMA digest buffer\n"); -+ rc = -ENOMEM; -+ goto err_engine_hash_start; -+ } ++#ifdef USE_INTERRUPTS ++static void aspeed_chassis_status_check(struct aspeed_chassis *chassis) ++{ ++ union chassis_ctrl_register chassis_ctrl; + -+ /* Hash engine hardware initial done, prepare queue lock */ -+ mutex_init(&hash_engine->queue_lock); ++ 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); ++ } + -+ return 0; ++ 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); ++ } + -+err_engine_hash_start: -+ crypto_engine_exit(hace_dev->crypt_engine_hash); -+end: -+ return rc; ++ 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); ++ } +} + -+void aspeed_hace_hash_remove(struct aspeed_hace_dev *hace_dev) ++static irqreturn_t aspeed_chassis_isr(int this_irq, void *dev_id) +{ -+ struct aspeed_engine_hash *hash_engine = &hace_dev->hash_engine; ++ struct aspeed_chassis *chassis = dev_id; + -+ crypto_engine_exit(hace_dev->crypt_engine_hash); -+ tasklet_kill(&hash_engine->done_task); ++ aspeed_chassis_status_check(chassis); ++ return IRQ_HANDLED; +} -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 2026-04-08 18:03:48.327705009 +0000 -@@ -6,15 +6,18 @@ - #include "aspeed-hace.h" - #include - #include -+#include - #include - #include - #include - #include - #include - #include -+#include -+#include -+#include - #include - #include --#include - - #ifdef CONFIG_CRYPTO_DEV_ASPEED_DEBUG - #define HACE_DBG(d, fmt, ...) \ -@@ -24,6 +27,45 @@ - dev_dbg((d)->dev, "%s() " fmt, __func__, ##__VA_ARGS__) - #endif - -+static unsigned char *dummy_key1; -+static unsigned char *dummy_key2; ++#endif + -+int find_dummy_key(const char *key, int keylen) ++static void aspeed_chassis_int_ctrl(struct aspeed_chassis *chassis, bool ctrl) +{ -+ 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; ++ union chassis_ctrl_register chassis_ctrl; + -+ return ret; ++ 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); +} + -+int aspeed_hace_reset(struct aspeed_hace_dev *hace_dev) -+{ -+ int rc; ++static const struct of_device_id aspeed_chassis_of_table[] = { ++ { .compatible = "aspeed,ast2600-chassis" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, aspeed_chassis_of_table); + -+ HACE_DBG(hace_dev, "\n"); ++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; + -+ if (!hace_dev->rst) -+ return -ENODEV; ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; + -+ rc = reset_control_assert(hace_dev->rst); -+ if (rc) { -+ dev_err(hace_dev->dev, "Hace reset failed (assert).\n"); -+ return rc; ++ 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; + } + -+ rc = reset_control_deassert(hace_dev->rst); -+ if (rc) { -+ dev_err(hace_dev->dev, "Hace reset failed (deassert).\n"); -+ return rc; ++ 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 + -+ return 0; ++ 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); +} + - /* HACE interrupt service routine */ - static irqreturn_t aspeed_hace_irq(int irq, void *dev) - { -@@ -51,23 +93,9 @@ - dev_warn(hace_dev->dev, "CRYPTO no active requests.\n"); - } ++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 -- return IRQ_HANDLED; --} -- --static void aspeed_hace_crypto_done_task(unsigned long data) --{ -- struct aspeed_hace_dev *hace_dev = (struct aspeed_hace_dev *)data; -- struct aspeed_engine_crypto *crypto_engine = &hace_dev->crypto_engine; -- -- crypto_engine->resume(hace_dev); --} -+ HACE_DBG(hace_dev, "handled\n"); +@@ -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 void aspeed_hace_hash_done_task(unsigned long data) --{ -- struct aspeed_hace_dev *hace_dev = (struct aspeed_hace_dev *)data; -- struct aspeed_engine_hash *hash_engine = &hace_dev->hash_engine; -- -- hash_engine->resume(hace_dev); -+ return IRQ_HANDLED; + static inline struct aspeed_pwm_tach_data * +@@ -282,12 +283,14 @@ + priv->base + TACH_ASPEED_CTRL(tach_ch)); } - static void aspeed_hace_register(struct aspeed_hace_dev *hace_dev) -@@ -93,30 +121,35 @@ - static const struct of_device_id aspeed_hace_of_matches[] = { - { .compatible = "aspeed,ast2500-hace", .data = (void *)5, }, - { .compatible = "aspeed,ast2600-hace", .data = (void *)6, }, -+ { .compatible = "aspeed,ast2700-hace", .data = (void *)7, }, - {}, - }; - - static int aspeed_hace_probe(struct platform_device *pdev) +-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) { -- struct aspeed_engine_crypto *crypto_engine; -- struct aspeed_engine_hash *hash_engine; -+ const struct of_device_id *hace_dev_id; - 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), - GFP_KERNEL); - if (!hace_dev) - return -ENOMEM; - -- hace_dev->version = (uintptr_t)device_get_match_data(&pdev->dev); -- if (!hace_dev->version) { -+ hace_dev_id = of_match_device(aspeed_hace_of_matches, &pdev->dev); -+ if (!hace_dev_id) { - dev_err(&pdev->dev, "Failed to match hace dev id\n"); - return -EINVAL; - } - - hace_dev->dev = &pdev->dev; -- hash_engine = &hace_dev->hash_engine; -- crypto_engine = &hace_dev->crypto_engine; -+ hace_dev->version = (unsigned long)hace_dev_id->data; + u64 rpm; + u32 tach_div; - platform_set_drvdata(pdev, hace_dev); +- 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; -@@ -149,115 +182,93 @@ - return rc; - } + 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); + } -- /* Initialize crypto hardware engine structure for hash */ -- hace_dev->crypt_engine_hash = crypto_engine_alloc_init(hace_dev->dev, -- true); -- if (!hace_dev->crypt_engine_hash) { -- rc = -ENOMEM; -- goto clk_exit; -- } -- -- rc = crypto_engine_start(hace_dev->crypt_engine_hash); -- if (rc) -- goto err_engine_hash_start; -- -- tasklet_init(&hash_engine->done_task, aspeed_hace_hash_done_task, -- (unsigned long)hace_dev); -- -- /* Initialize crypto hardware engine structure for crypto */ -- hace_dev->crypt_engine_crypto = crypto_engine_alloc_init(hace_dev->dev, -- true); -- if (!hace_dev->crypt_engine_crypto) { -- rc = -ENOMEM; -- goto err_engine_hash_start; -- } -- -- rc = crypto_engine_start(hace_dev->crypt_engine_crypto); -- if (rc) -- goto err_engine_crypto_start; -- -- tasklet_init(&crypto_engine->done_task, aspeed_hace_crypto_done_task, -- (unsigned long)hace_dev); -- -- /* Allocate DMA buffer for hash engine input used */ -- hash_engine->ahash_src_addr = -- dmam_alloc_coherent(&pdev->dev, -- ASPEED_HASH_SRC_DMA_BUF_LEN, -- &hash_engine->ahash_src_dma_addr, -- GFP_KERNEL); -- if (!hash_engine->ahash_src_addr) { -- dev_err(&pdev->dev, "Failed to allocate dma buffer\n"); -- rc = -ENOMEM; -- goto err_engine_crypto_start; -- } -- -- /* Allocate DMA buffer for crypto engine context used */ -- crypto_engine->cipher_ctx = -- dmam_alloc_coherent(&pdev->dev, -- PAGE_SIZE, -- &crypto_engine->cipher_ctx_dma, -- GFP_KERNEL); -- if (!crypto_engine->cipher_ctx) { -- dev_err(&pdev->dev, "Failed to allocate cipher ctx dma\n"); -- rc = -ENOMEM; -- goto err_engine_crypto_start; -- } -- -- /* Allocate DMA buffer for crypto engine input used */ -- crypto_engine->cipher_addr = -- dmam_alloc_coherent(&pdev->dev, -- ASPEED_CRYPTO_SRC_DMA_BUF_LEN, -- &crypto_engine->cipher_dma_addr, -- GFP_KERNEL); -- if (!crypto_engine->cipher_addr) { -- dev_err(&pdev->dev, "Failed to allocate cipher addr dma\n"); -- rc = -ENOMEM; -- goto err_engine_crypto_start; -- } -- -- /* Allocate DMA buffer for crypto engine output used */ -- if (hace_dev->version == AST2600_VERSION) { -- crypto_engine->dst_sg_addr = -- dmam_alloc_coherent(&pdev->dev, -- ASPEED_CRYPTO_DST_DMA_BUF_LEN, -- &crypto_engine->dst_sg_dma_addr, -- GFP_KERNEL); -- if (!crypto_engine->dst_sg_addr) { -- 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 = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); -+ if (rc) { -+ dev_warn(&pdev->dev, "No suitable DMA available\n"); -+ return rc; -+ } -+ -+ /* Init mutex lock for supporting hace concurrent*/ -+ sema_init(&hace_dev->lock, 1); -+ -+#ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_HASH -+ rc = aspeed_hace_hash_init(hace_dev); -+ if (rc) { -+ dev_err(&pdev->dev, "Hash init failed\n"); -+ return rc; -+ } -+#endif -+#ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_CRYPTO -+ rc = aspeed_hace_crypto_init(hace_dev); -+ if (rc) { -+ 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); - - dev_info(&pdev->dev, "Aspeed Crypto Accelerator successfully registered\n"); - - return 0; -- --err_engine_crypto_start: -- crypto_engine_exit(hace_dev->crypt_engine_crypto); --err_engine_hash_start: -- crypto_engine_exit(hace_dev->crypt_engine_hash); --clk_exit: -- clk_disable_unprepare(hace_dev->clk); -- -- return rc; - } - - static void aspeed_hace_remove(struct platform_device *pdev) - { - struct aspeed_hace_dev *hace_dev = platform_get_drvdata(pdev); -- struct aspeed_engine_crypto *crypto_engine = &hace_dev->crypto_engine; -- struct aspeed_engine_hash *hash_engine = &hace_dev->hash_engine; - - aspeed_hace_unregister(hace_dev); - -- crypto_engine_exit(hace_dev->crypt_engine_hash); -- crypto_engine_exit(hace_dev->crypt_engine_crypto); -+#ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_HASH -+ aspeed_hace_hash_remove(hace_dev); -+#endif + 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; -- tasklet_kill(&hash_engine->done_task); -- tasklet_kill(&crypto_engine->done_task); -+#ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_CRYPTO -+ aspeed_hace_crypto_remove(hace_dev); -+#endif + 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)); - clk_disable_unprepare(hace_dev->clk); + aspeed_tach_ch_enable(priv, ch, true); +@@ -452,6 +455,50 @@ + reset_control_assert(rst); } -@@ -266,7 +277,7 @@ - - static struct platform_driver aspeed_hace_driver = { - .probe = aspeed_hace_probe, -- .remove_new = aspeed_hace_remove, -+ .remove = aspeed_hace_remove, - .driver = { - .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 2026-04-08 18:03:48.327705009 +0000 -@@ -10,6 +10,8 @@ - #include - #include - #include -+#include -+#include - - /***************************** - * * -@@ -23,7 +25,7 @@ - #define ASPEED_HACE_CMD 0x10 /* Crypto Engine Command Register */ - - /* G5 */ --#define ASPEED_HACE_TAG 0x18 /* HACE Tag Register */ -+#define ASPEED_HACE_TAG 0x18 /* HACE Tag Write Buffer Base Address Register */ - /* 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 @@ - #define ASPEED_HACE_HASH_DATA_LEN 0x2C /* Hash Data Length Register */ - #define ASPEED_HACE_HASH_CMD 0x30 /* Hash Engine Command Register */ - -+/* G7 */ -+#define ASPEED_HACE_SRC_H 0x80 /* Crypto Data Source Base High Address Register */ -+#define ASPEED_HACE_DEST_H 0x84 /* Crypto Data Destination Base High Address Register */ -+#define ASPEED_HACE_CONTEXT_H 0x88 /* Crypto Context Buffer Base High Address Register */ -+#define ASPEED_HACE_TAG_H 0x8C /* HACE Tag Write Buffer Base High Address Register */ -+#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 */ -+ - /* crypto cmd */ - #define HACE_CMD_SINGLE_DES 0 - #define HACE_CMD_TRIPLE_DES BIT(17) -@@ -109,8 +120,9 @@ - - #define CRYPTO_FLAGS_BUSY BIT(1) --#define SHA_OP_UPDATE 1 --#define SHA_OP_FINAL 2 -+#define SHA_OP_INIT BIT(0) -+#define SHA_OP_UPDATE BIT(1) -+#define SHA_OP_FINAL BIT(2) - - #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) - -+#define DUMMY_KEY_SIZE 32 -+ - struct aspeed_hace_dev; - struct scatterlist; - -@@ -147,10 +161,21 @@ - unsigned long flags; - struct ahash_request *req; - -+ /* Protects hash engine operation enqueue in order */ -+ struct mutex queue_lock; -+ - /* input buffer */ - void *ahash_src_addr; - dma_addr_t ahash_src_dma_addr; - -+ /* remain data buffer */ -+ u8 *buffer_addr; -+ dma_addr_t buffer_dma_addr; -+ -+ /* output buffer */ -+ void *digest_addr; -+ dma_addr_t digest_dma_addr; -+ - dma_addr_t src_dma; - dma_addr_t digest_dma; - -@@ -192,12 +217,10 @@ - - /* remain data buffer */ - u8 buffer[SHA512_BLOCK_SIZE * 2]; -- dma_addr_t buffer_dma_addr; - size_t bufcnt; /* buffer counter */ - - /* output buffer */ -- u8 digest[SHA512_DIGEST_SIZE] __aligned(64); -- dma_addr_t digest_dma_addr; -+ u8 digest[SHA512_DIGEST_SIZE]; - u64 digcnt[2]; - }; - -@@ -220,12 +243,14 @@ - - /* callback func */ - aspeed_hace_fn_t resume; -+ int load_vault_key; - }; - - struct aspeed_cipher_ctx { - struct aspeed_hace_dev *hace_dev; - int key_len; - u8 key[AES_MAX_KEYLENGTH]; -+ int dummy_key; - - /* callback func */ - aspeed_hace_fn_t start; -@@ -243,11 +268,16 @@ - - struct aspeed_hace_dev { - void __iomem *regs; -+ void __iomem *sec_regs; - struct device *dev; - int irq; - struct clk *clk; -+ struct reset_control *rst; - unsigned long version; - -+ /* Protects hace register access */ -+ struct semaphore lock; -+ - struct crypto_engine *crypt_engine_hash; - struct crypto_engine *crypt_engine_crypto; - -@@ -268,7 +298,8 @@ - - enum aspeed_version { - AST2500_VERSION = 5, -- AST2600_VERSION -+ AST2600_VERSION, -+ AST2700_VERSION, - }; - - #define ast_hace_write(hace, val, offset) \ -@@ -280,5 +311,11 @@ - 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_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 2026-04-08 18:03:48.327705009 +0000 -@@ -0,0 +1,901 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright 2023 Aspeed Technology Inc. -+ */ -+ -+#include -+#include -+#include -+#include "aspeed-rsss.h" -+ -+//#define RSSS_SHA3_POLLING_MODE -+ -+static int aspeed_sha3_self_test(struct aspeed_rsss_dev *rsss_dev) ++static void aspeed_pwm_set_wdt_reload(struct pwm_chip *chip, ++ struct pwm_device *pwm, ++ u64 reload_duty_cycle) +{ -+ u32 pattern = 0xbeef; -+ u32 val; -+ -+ ast_rsss_write(rsss_dev, pattern, ASPEED_SHA3_SRC_LO); -+ val = ast_rsss_read(rsss_dev, ASPEED_SHA3_SRC_LO); -+ if (val != pattern) -+ return -EIO; ++ struct aspeed_pwm_tach_data *priv = aspeed_pwm_chip_to_data(chip); ++ u32 hwpwm = pwm->hwpwm, val; + -+ ast_rsss_write(rsss_dev, 0x0, ASPEED_SHA3_SRC_LO); -+ val = ast_rsss_read(rsss_dev, ASPEED_SHA3_SRC_LO); -+ if (val) -+ return -EIO; ++ 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)); + -+ return 0; ++ 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 int aspeed_sha3_dma_prepare(struct aspeed_rsss_dev *rsss_dev) ++static struct pwm_device * ++aspeed_pwm_xlate(struct pwm_chip *chip, const struct of_phandle_args *args) +{ -+ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; -+ struct ahash_request *req = sha3_engine->req; -+ struct aspeed_sha3_reqctx *rctx; -+ int length, remain; -+ -+ rctx = ahash_request_ctx(req); -+ remain = (rctx->total + rctx->bufcnt) % rctx->blksize; -+ length = rctx->total + rctx->bufcnt - remain; -+ -+ RSSS_DBG(rsss_dev, "%s:0x%x, %s:%zu, %s:0x%x, %s:0x%x, %s:0x%x\n", -+ "rctx total", rctx->total, "bufcnt", rctx->bufcnt, -+ "offset", rctx->offset, "length", length, -+ "remain", remain); ++ struct pwm_device *pwm; + -+ if (rctx->bufcnt) -+ memcpy(sha3_engine->ahash_src_addr, rctx->buffer, -+ rctx->bufcnt); ++ /* period in the second cell and flags in the third cell are optional */ ++ if (args->args_count < 1) ++ return ERR_PTR(-EINVAL); + -+ if (length < ASPEED_HASH_SRC_DMA_BUF_LEN) { -+ scatterwalk_map_and_copy(sha3_engine->ahash_src_addr + rctx->bufcnt, -+ rctx->src_sg, rctx->offset, -+ rctx->total - remain, 0); -+ rctx->offset += rctx->total - remain; ++ pwm = pwm_request_from_chip(chip, args->args[0], NULL); ++ if (IS_ERR(pwm)) ++ return pwm; + -+ } else { -+ dev_warn(rsss_dev->dev, "SHA3 input data length is too large\n"); -+ return -EINVAL; -+ } ++ if (args->args_count > 1) ++ pwm->args.period = args->args[1]; + -+ /* Copy remain data into buffer */ -+ scatterwalk_map_and_copy(rctx->buffer, rctx->src_sg, -+ rctx->offset, remain, 0); -+ rctx->bufcnt = remain; ++ pwm->args.polarity = PWM_POLARITY_NORMAL; ++ if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED) ++ pwm->args.polarity = PWM_POLARITY_INVERSED; + -+ sha3_engine->src_length = length; -+ sha3_engine->src_dma = sha3_engine->ahash_src_dma_addr; ++ if (args->args_count > 3 && args->args[3] < U8_MAX) ++ aspeed_pwm_set_wdt_reload(chip, pwm, args->args[3]); + -+ return 0; ++ return pwm; +} + -+/* -+ * Prepare DMA buffer as SG list buffer before -+ * hardware engine processing. -+ */ -+static int aspeed_sha3_dma_prepare_sg(struct aspeed_rsss_dev *rsss_dev) -+{ -+ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; -+ struct ahash_request *req = sha3_engine->req; -+ struct aspeed_sha3_reqctx *rctx; -+ struct aspeed_sg_list *src_list; -+ struct scatterlist *s; -+ int length, remain, sg_len; -+ int i, rc = 0; + 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; + -+ rctx = ahash_request_ctx(req); -+ remain = (rctx->total + rctx->bufcnt) % rctx->blksize; -+ length = rctx->total + rctx->bufcnt - remain; + 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. + -+ RSSS_DBG(rsss_dev, "%s:0x%x, %s:%zu, %s:0x%x, %s:0x%x\n", -+ "rctx total", rctx->total, "bufcnt", rctx->bufcnt, -+ "length", length, "remain", remain); ++ This driver can also be built as a module. If so, the module ++ will be called i2c-ast2600. + -+ sg_len = dma_map_sg(rsss_dev->dev, rctx->src_sg, rctx->src_nents, -+ DMA_TO_DEVICE); -+ /* -+ * Need dma_sync_sg_for_device()? -+ */ -+ if (!sg_len) { -+ dev_warn(rsss_dev->dev, "dma_map_sg() src error\n"); -+ rc = -ENOMEM; -+ goto end; -+ } -+ -+ src_list = (struct aspeed_sg_list *)sha3_engine->ahash_src_addr; + 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 + -+ if (rctx->bufcnt != 0) { -+ u64 phy_addr; -+ u32 len; ++#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 + -+ phy_addr = sha3_engine->buffer_dma_addr; -+ len = rctx->bufcnt; -+ length -= len; ++#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 + -+ /* Last sg list */ -+ if (length == 0) -+ len |= SG_LAST_LIST; ++/* 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) + -+ src_list[0].phy_addr = cpu_to_le64(phy_addr); -+ src_list[0].len = cpu_to_le32(len); ++/* 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) + -+ RSSS_DBG(rsss_dev, "Remain buffer first, addr:%llx, len:0x%x\n", -+ src_list[0].phy_addr, src_list[0].len); ++/* 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) + -+ src_list++; -+ } ++#define AST2600_I2CC_SCL_LINE_STS BIT(18) ++#define AST2600_I2CC_SDA_LINE_STS BIT(17) ++#define AST2600_I2CC_BUS_BUSY_STS BIT(16) + -+ if (length != 0) { -+ for_each_sg(rctx->src_sg, s, sg_len, i) { -+ u64 phy_addr = sg_dma_address(s); -+ u32 len = sg_dma_len(s); -+ u8 *va = sg_virt(s); ++#define AST2600_I2CC_GET_RX_BUFF(x) (((x) >> 8) & GENMASK(7, 0)) + -+ RSSS_DBG(rsss_dev, "SG[%d] PA:%llx, VA:%llx, len:0x%x\n", -+ i, sg_dma_address(s), (u64)va, len); ++/* 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) + -+ if (length > len) { -+ length -= len; -+ } else { -+ /* Last sg list */ -+ len = length; -+ len |= SG_LAST_LIST; -+ length = 0; -+ } ++/* 0x10 : I2CM Controller Interrupt Control Register */ ++#define AST2600_I2CM_IER 0x10 ++/* 0x14 : I2CM Controller Interrupt Status Register : WC */ ++#define AST2600_I2CM_ISR 0x14 + -+ src_list[i].phy_addr = cpu_to_le64(phy_addr); -+ src_list[i].len = cpu_to_le32(len); ++#define AST2600_I2CM_ISR_MASK GENMASK(31, 21) ++#define AST2600_I2CM_SW_ISR_MASK GENMASK(31, 19) + -+ len = len & 0xffff; -+ } -+ } ++#define AST2600_I2CM_PKT_TIMEOUT BIT(18) ++#define AST2600_I2CM_PKT_ERROR BIT(17) ++#define AST2600_I2CM_PKT_DONE BIT(16) + -+ if (length != 0) { -+ rc = -EINVAL; -+ goto free_src_sg; -+ } ++#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) + -+ rctx->offset = rctx->total - remain; -+ sha3_engine->src_length = rctx->total + rctx->bufcnt - remain; -+ sha3_engine->src_dma = sha3_engine->ahash_src_dma_addr; ++#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) + -+ return 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) + -+free_src_sg: -+ RSSS_DBG(rsss_dev, "dma_unmap_sg()\n"); -+ dma_unmap_sg(rsss_dev->dev, rctx->src_sg, rctx->src_nents, -+ DMA_TO_DEVICE); -+end: -+ return rc; -+} ++#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) + -+static int aspeed_sha3_complete(struct aspeed_rsss_dev *rsss_dev) -+{ -+ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; -+ struct ahash_request *req = sha3_engine->req; ++#define AST2600_I2CM_TX_CMD BIT(1) ++#define AST2600_I2CM_START_CMD BIT(0) + -+ RSSS_DBG(rsss_dev, "\n"); ++/* 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)) + -+ sha3_engine->flags &= ~CRYPTO_FLAGS_BUSY; ++/* 0x20 : I2CS Target Interrupt Control Register */ ++#define AST2600_I2CS_IER 0x20 ++/* 0x24 : I2CS Target Interrupt Status Register */ ++#define AST2600_I2CS_ISR 0x24 + -+ crypto_finalize_hash_request(rsss_dev->crypt_engine_sha3, req, 0); ++#define AST2600_I2CS_ADDR_INDICATE_MASK GENMASK(31, 30) ++#define AST2600_I2CS_SLAVE_PENDING BIT(29) ++#define AST2600_I2CS_SADDR_PENDING BIT(28) + -+ return 0; -+} ++#define AST2600_I2CS_WAIT_TX_DMA BIT(25) ++#define AST2600_I2CS_WAIT_RX_DMA BIT(24) + -+/* -+ * Copy digest to the corresponding request result. -+ * This function will be called at final() stage. -+ */ -+static int aspeed_sha3_transfer(struct aspeed_rsss_dev *rsss_dev) -+{ -+ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; -+ struct ahash_request *req = sha3_engine->req; -+ struct aspeed_sha3_reqctx *rctx; ++#define AST2600_I2CS_ADDR3_NAK BIT(22) ++#define AST2600_I2CS_ADDR2_NAK BIT(21) ++#define AST2600_I2CS_ADDR1_NAK BIT(20) + -+ RSSS_DBG(rsss_dev, "\n"); ++#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) + -+ rctx = ahash_request_ctx(req); ++#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) + -+ /* add usleep for DMA done */ -+ udelay(8); -+ memcpy(req->result, sha3_engine->digest_addr, rctx->digsize); ++/* 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 aspeed_sha3_complete(rsss_dev); -+} ++#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) + -+#ifdef RSSS_SHA3_POLLING_MODE -+static int aspeed_sha3_wait_complete(struct aspeed_rsss_dev *rsss_dev) -+{ -+ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; -+ u32 sts; -+ int ret; ++#define AST2600_I2CS_TX_CMD BIT(2) + -+ ret = readl_poll_timeout(rsss_dev->regs + ASPEED_SHA3_BUSY_STS, sts, -+ ((sts & SHA3_STS) == 0x0), -+ ASPEED_RSSS_POLLING_TIME, -+ ASPEED_RSSS_TIMEOUT * 10); -+ if (ret) { -+ dev_err(rsss_dev->dev, "SHA3 wrong engine status\n"); -+ return -EIO; -+ } ++#define AST2600_I2CS_DMA_LEN 0x2C + -+ ret = readl_poll_timeout(rsss_dev->regs + ASPEED_RSSS_INT_STS, sts, -+ ((sts & SHA3_INT_DONE) == SHA3_INT_DONE), -+ ASPEED_RSSS_POLLING_TIME, -+ ASPEED_RSSS_TIMEOUT); -+ if (ret) { -+ dev_err(rsss_dev->dev, "SHA3 wrong interrupt status\n"); -+ return -EIO; -+ } ++/* 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)) + -+ ast_rsss_write(rsss_dev, sts, ASPEED_RSSS_INT_STS); ++/* 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 + -+ RSSS_DBG(rsss_dev, "irq sts:0x%x\n", sts); ++/* 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 + -+ if (sts & SHA3_INT_DONE) { -+ if (sha3_engine->flags & CRYPTO_FLAGS_BUSY) -+ tasklet_schedule(&sha3_engine->done_task); -+ else -+ dev_err(rsss_dev->dev, "SHA3 no active requests.\n"); -+ } ++#define AST2600_I2CS_ADDR_CTRL 0x40 + -+ return 0; -+} -+#endif ++#define AST2600_I2CS_ADDR3_MASK GENMASK(22, 16) ++#define AST2600_I2CS_ADDR2_MASK GENMASK(14, 8) ++#define AST2600_I2CS_ADDR1_MASK GENMASK(6, 0) + -+/* -+ * Trigger hardware engines to do the math. -+ */ -+static int aspeed_sha3_trigger(struct aspeed_rsss_dev *rsss_dev, -+ aspeed_rsss_fn_t resume) -+{ -+ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; -+ struct ahash_request *req = sha3_engine->req; -+ struct aspeed_sha3_reqctx *rctx; ++#define AST2600_I2CM_DMA_LEN_STS 0x48 ++#define AST2600_I2CS_DMA_LEN_STS 0x4C + -+ RSSS_DBG(rsss_dev, "src_dma:%pad, digest_dma:%pad, length:%zu\n", -+ &sha3_engine->src_dma, &sha3_engine->digest_dma_addr, -+ sha3_engine->src_length); ++#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) + -+ rctx = ahash_request_ctx(req); -+ sha3_engine->resume = resume; ++/* 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) + -+ memcpy(sha3_engine->digest_addr, rctx->digest, rctx->digsize); -+ memcpy(sha3_engine->buffer_addr, rctx->buffer, rctx->bufcnt); ++/* 0x74 : Target Device Address Register */ ++#define MSIC_CONFIG_ACTIMING1 0x74 ++#define MSIC_I2C_SET_TIMEOUT(s, m) (((s) << 16) | (m)) + -+ ast_rsss_write(rsss_dev, sha3_engine->src_dma, -+ ASPEED_SHA3_SRC_LO); -+ /* TODO - SRC_HI */ -+ ast_rsss_write(rsss_dev, sha3_engine->src_dma >> 32, -+ ASPEED_SHA3_SRC_HI); ++/* 0x78 : Misc status */ ++#define MSIC_STATUS 0x78 + -+ ast_rsss_write(rsss_dev, sha3_engine->digest_dma_addr, -+ ASPEED_SHA3_DST_LO); -+ /* TODO - DST_HI */ -+ ast_rsss_write(rsss_dev, sha3_engine->digest_dma_addr >> 32, -+ ASPEED_SHA3_DST_HI); ++/* 0x84 : Byte data log */ ++#define BYTE_DATA_LOG 0x84 + -+ if (!sha3_engine->sg_mode) -+ ast_rsss_write(rsss_dev, sha3_engine->src_length, -+ ASPEED_SHA3_SRC_LEN); ++#define AST2700_I2CC_GET_BUFF(x) ((x) & GENMASK(7, 0)) + -+ ast_rsss_write(rsss_dev, rctx->cmd, ASPEED_SHA3_CMD); ++/* 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) + -+ /* Memory barrier to ensure all data setup before engine starts */ -+ mb(); ++/* 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 + -+ rctx->cmd |= SHA3_CMD_TRIG; ++#define I2C_TARGET_MSG_BUF_SIZE 4096 + -+ RSSS_DBG(rsss_dev, "cmd:0x%x\n", rctx->cmd); ++#define AST2600_I2C_DMA_SIZE 4096 + -+ ast_rsss_write(rsss_dev, rctx->cmd, ASPEED_SHA3_CMD); ++#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) + -+#ifdef RSSS_SHA3_POLLING_MODE -+ return aspeed_sha3_wait_complete(rsss_dev); -+#else -+ return -EINPROGRESS; -+#endif -+} ++#define AST2600_I2C_TIMEOUT_CLK 0x1 ++#define AST2700_I2C_TIMEOUT_CLK 0x3 + -+static int aspeed_sha3_req_final(struct aspeed_rsss_dev *rsss_dev) -+{ -+ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; -+ struct ahash_request *req = sha3_engine->req; -+ struct aspeed_sha3_reqctx *rctx = ahash_request_ctx(req); -+ int remain_pad; -+ u8 *src; ++#define AST2600_I2C_TARGET_COUNT 0x3 + -+ RSSS_DBG(rsss_dev, "\n"); ++enum xfer_mode { ++ BYTE_MODE, ++ BUFF_MODE, ++ DMA_MODE, ++}; + -+ /* A0 padding issue */ -+ remain_pad = rctx->blksize - rctx->bufcnt; -+ if (remain_pad < 16) { -+ /* SW padding */ -+ RSSS_DBG(rsss_dev, "Use SW padding, pad size:0x%x\n", -+ remain_pad); -+ src = (u8 *)rctx->buffer; -+ src[rctx->bufcnt] = 0x06; -+ memset(src + rctx->bufcnt + 1, 0, remain_pad - 1); -+ src[rctx->bufcnt + remain_pad - 1] |= 0x80; ++enum i2c_version { ++ AST2600, ++ AST2700, ++}; + -+ rctx->bufcnt += remain_pad; ++struct i2c_divisor { ++ u32 baseclk_idx; ++ u32 divisor; ++ u8 baseclk_limit; ++}; + -+ } else { -+ rctx->cmd |= SHA3_CMD_HW_PAD; -+ } ++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 ++}; + -+ if (sha3_engine->sg_mode) { -+ struct aspeed_sg_list *src_list = -+ (struct aspeed_sg_list *)sha3_engine->ahash_src_addr; -+ u64 phy_addr; -+ u32 len; ++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; + -+ phy_addr = sha3_engine->buffer_dma_addr; -+ len = rctx->bufcnt; -+ len |= SG_LAST_LIST; ++ regmap_read(i2c_bus->global_regs, AST2600_I2CG_CLK_DIV_CTRL, &clk_div_reg); + -+ src_list[0].phy_addr = cpu_to_le64(phy_addr); -+ src_list[0].len = cpu_to_le32(len); -+ -+ RSSS_DBG(rsss_dev, "Final SG, addr:%llx, len:0x%x\n", -+ src_list[0].phy_addr, src_list[0].len); -+ -+ rctx->cmd |= SHA3_CMD_SG_MODE; -+ sha3_engine->src_dma = sha3_engine->ahash_src_dma_addr; -+ -+ } else { -+ sha3_engine->src_dma = sha3_engine->buffer_dma_addr; -+ sha3_engine->src_length = rctx->bufcnt; ++ 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; ++ } + } + -+ rctx->cmd |= SHA3_CMD_ACC_FINAL; -+ -+ return aspeed_sha3_trigger(rsss_dev, aspeed_sha3_transfer); -+} -+ -+static int aspeed_sha3_update_resume(struct aspeed_rsss_dev *rsss_dev) -+{ -+ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; -+ struct ahash_request *req = sha3_engine->req; -+ struct aspeed_sha3_reqctx *rctx; -+ -+ RSSS_DBG(rsss_dev, "\n"); -+ -+ rctx = ahash_request_ctx(req); -+ -+ memcpy(rctx->digest, sha3_engine->digest_addr, rctx->digsize); -+ rctx->cmd &= ~SHA3_CMD_TRIG; ++ 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; + -+ if (rctx->flags & SHA3_FLAGS_FINUP) -+ return aspeed_sha3_req_final(rsss_dev); ++ 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); ++ } + -+ return aspeed_sha3_complete(rsss_dev); ++ writel(data, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); +} + -+static int aspeed_sha3_update_resume_sg(struct aspeed_rsss_dev *rsss_dev) ++static void ast2700_i2c_ac_timing_config(struct ast2600_i2c_bus *i2c_bus) +{ -+ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; -+ struct ahash_request *req = sha3_engine->req; -+ struct aspeed_sha3_reqctx *rctx; -+ int remain; -+ -+ RSSS_DBG(rsss_dev, "\n"); -+ -+ rctx = ahash_request_ctx(req); -+ -+ memcpy(rctx->digest, sha3_engine->digest_addr, rctx->digsize); -+ remain = rctx->total - rctx->offset; -+ -+ RSSS_DBG(rsss_dev, "Copy remain data from 0x%x, size:0x%x\n", -+ rctx->offset, remain); -+ -+ dma_unmap_sg(rsss_dev->dev, rctx->src_sg, rctx->src_nents, -+ DMA_TO_DEVICE); -+ -+ scatterwalk_map_and_copy(rctx->buffer, rctx->src_sg, rctx->offset, -+ remain, 0); -+ -+ rctx->bufcnt = remain; -+ rctx->cmd &= ~(SHA3_CMD_TRIG | SHA3_CMD_SG_MODE); -+ -+ if (rctx->flags & SHA3_FLAGS_FINUP) -+ return aspeed_sha3_req_final(rsss_dev); ++ 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; + -+ return aspeed_sha3_complete(rsss_dev); -+} ++ /* 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; ++ } + -+static int aspeed_sha3_req_update(struct aspeed_rsss_dev *rsss_dev) -+{ -+ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; -+ struct ahash_request *req = sha3_engine->req; -+ struct aspeed_sha3_reqctx *rctx; -+ aspeed_rsss_fn_t resume; -+ int ret; ++ regmap_read(i2c_bus->global_regs, AST2600_I2CG_CLK_DIV_CTRL, &clk_div_reg); + -+ RSSS_DBG(rsss_dev, "\n"); ++ /* 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; ++ } ++ } + -+ rctx = ahash_request_ctx(req); ++ /* 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 (sha3_engine->sg_mode) { -+ rctx->cmd |= SHA3_CMD_SG_MODE; -+ resume = aspeed_sha3_update_resume_sg; ++ 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; + -+ } else { -+ resume = aspeed_sha3_update_resume; ++ 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); + } + -+ ret = sha3_engine->dma_prepare(rsss_dev); -+ if (ret) -+ return ret; -+ -+ return aspeed_sha3_trigger(rsss_dev, resume); ++ writel(data, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); +} + -+static int aspeed_sha3_do_request(struct crypto_engine *engine, void *areq) ++static int ast2600_i2c_recover_bus(struct ast2600_i2c_bus *i2c_bus) +{ -+ struct ahash_request *req = ahash_request_cast(areq); -+ struct aspeed_sha3_reqctx *rctx = ahash_request_ctx(req); -+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); -+ struct aspeed_sha3_ctx *tctx = crypto_ahash_ctx(tfm); -+ struct aspeed_rsss_dev *rsss_dev = tctx->rsss_dev; -+ struct aspeed_engine_sha3 *sha3_engine; ++ u32 state = readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF); + int ret = 0; ++ int r; + -+ RSSS_DBG(rsss_dev, "\n"); -+ -+ sha3_engine = &rsss_dev->sha3_engine; -+ sha3_engine->flags |= CRYPTO_FLAGS_BUSY; -+ sha3_engine->req = req; -+ -+ if (sha3_engine->sg_mode) -+ sha3_engine->dma_prepare = aspeed_sha3_dma_prepare_sg; -+ else -+ sha3_engine->dma_prepare = aspeed_sha3_dma_prepare; -+ -+ if (rctx->op == SHA_OP_UPDATE) -+ ret = aspeed_sha3_req_update(rsss_dev); -+ else if (rctx->op == SHA_OP_FINAL) -+ ret = aspeed_sha3_req_final(rsss_dev); -+ -+ if (ret != -EINPROGRESS) -+ return ret; -+ -+ return 0; -+} ++ dev_dbg(i2c_bus->dev, "%d-bus recovery bus [%x]\n", i2c_bus->adap.nr, state); + -+static int aspeed_sha3_handle_queue(struct aspeed_rsss_dev *rsss_dev, -+ struct ahash_request *req) -+{ -+ struct aspeed_sha3_reqctx *rctx = ahash_request_ctx(req); -+ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; -+ int ret = 0; ++ reinit_completion(&i2c_bus->cmd_complete); ++ i2c_bus->cmd_err = 0; + -+ if (rctx->op & SHA_OP_INIT) { -+ mutex_lock(&sha3_engine->queue_lock); -+ return 0; ++ /* 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; ++ } + } + -+ ret = crypto_transfer_hash_request_to_engine(rsss_dev->crypt_engine_sha3, -+ req); -+ -+ /* The last request is enqueued, release the lock */ -+ if (rctx->op & SHA_OP_FINAL || rctx->flags & SHA3_FLAGS_FINUP) -+ mutex_unlock(&sha3_engine->queue_lock); ++ /* 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; ++ } + + return ret; +} + -+static int aspeed_sha3_update(struct ahash_request *req) ++#if IS_ENABLED(CONFIG_I2C_SLAVE) ++static void ast2700_i2c_get_target(struct ast2600_i2c_bus *i2c_bus, u8 addr) +{ -+ struct aspeed_sha3_reqctx *rctx = ahash_request_ctx(req); -+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); -+ struct aspeed_sha3_ctx *tctx = crypto_ahash_ctx(tfm); -+ struct aspeed_rsss_dev *rsss_dev = tctx->rsss_dev; -+ struct aspeed_engine_sha3 *sha3_engine; -+ -+ RSSS_DBG(rsss_dev, "req->nbytes: %d\n", req->nbytes); -+ -+ sha3_engine = &rsss_dev->sha3_engine; -+ -+ rctx->total = req->nbytes; -+ rctx->src_sg = req->src; -+ rctx->offset = 0; -+ rctx->src_nents = sg_nents(req->src); -+ rctx->op = SHA_OP_UPDATE; -+ -+ RSSS_DBG(rsss_dev, "total:0x%x, src_nents:0x%x\n", rctx->total, rctx->src_nents); -+ -+ rctx->digcnt[0] += rctx->total; -+ if (rctx->digcnt[0] < rctx->total) -+ rctx->digcnt[1]++; -+ -+ if (rctx->bufcnt + rctx->total < rctx->blksize) { -+ scatterwalk_map_and_copy(rctx->buffer + rctx->bufcnt, -+ rctx->src_sg, rctx->offset, -+ rctx->total, 0); -+ rctx->bufcnt += rctx->total; ++ u8 i = 0; ++ bool target_find = false; + -+ return 0; ++ /* 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 aspeed_sha3_handle_queue(rsss_dev, req); -+} -+ -+static int aspeed_sha3_final(struct ahash_request *req) -+{ -+ struct aspeed_sha3_reqctx *rctx = ahash_request_ctx(req); -+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); -+ struct aspeed_sha3_ctx *tctx = crypto_ahash_ctx(tfm); -+ struct aspeed_rsss_dev *rsss_dev = tctx->rsss_dev; -+ -+ RSSS_DBG(rsss_dev, "req->nbytes:%d, rctx->total:%d\n", -+ req->nbytes, rctx->total); -+ rctx->op = SHA_OP_FINAL; -+ -+ return aspeed_sha3_handle_queue(rsss_dev, req); ++ if (!target_find) ++ dev_err(i2c_bus->dev, "address [%x] could not find\n", addr); +} + -+static int aspeed_sha3_finup(struct ahash_request *req) ++static void ast2700_i2c_target_packet_dma_irq(struct ast2600_i2c_bus *i2c_bus, u32 isr) +{ -+ struct aspeed_sha3_reqctx *rctx = ahash_request_ctx(req); -+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); -+ struct aspeed_sha3_ctx *tctx = crypto_ahash_ctx(tfm); -+ struct aspeed_rsss_dev *rsss_dev = tctx->rsss_dev; -+ int rc1, rc2; -+ -+ RSSS_DBG(rsss_dev, "req->nbytes: %d\n", req->nbytes); -+ -+ rctx->flags |= SHA3_FLAGS_FINUP; -+ -+ rc1 = aspeed_sha3_update(req); -+ if (rc1 == -EINPROGRESS || rc1 == -EBUSY) -+ return rc1; ++ int target_rx_len = 0; ++ u32 cmd = 0; ++ u8 value; ++ int i; ++ u32 sirq_log; ++ u32 sts; + -+ /* -+ * final() has to be always called to cleanup resources -+ * even if update() failed, except EINPROGRESS -+ */ -+ rc2 = aspeed_sha3_final(req); ++ 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); + -+ return rc1 ? : rc2; -+} ++ 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; + -+static int aspeed_sha3_init(struct ahash_request *req) -+{ -+ struct aspeed_sha3_reqctx *rctx = ahash_request_ctx(req); -+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); -+ struct aspeed_sha3_ctx *tctx = crypto_ahash_ctx(tfm); -+ struct aspeed_rsss_dev *rsss_dev = tctx->rsss_dev; ++ 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; ++ } + -+ RSSS_DBG(rsss_dev, "%s: digest size:%d\n", -+ crypto_tfm_alg_name(&tfm->base), -+ crypto_ahash_digestsize(tfm)); ++ 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; ++ } + -+ rctx->cmd = SHA3_CMD_ACC; -+ rctx->op = SHA_OP_INIT; -+ rctx->flags = 0; ++ sts &= ~(AST2600_I2CS_PKT_DONE | AST2600_I2CS_PKT_ERROR); + -+ switch (crypto_ahash_digestsize(tfm)) { -+ case SHA3_224_DIGEST_SIZE: -+ rctx->cmd |= SHA3_CMD_MODE_224; -+ rctx->flags |= SHA3_FLAGS_SHA224; -+ rctx->digsize = SHA3_224_DIGEST_SIZE; -+ rctx->blksize = SHA3_224_BLOCK_SIZE; ++ 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 SHA3_256_DIGEST_SIZE: -+ rctx->cmd |= SHA3_CMD_MODE_256; -+ rctx->flags |= SHA3_FLAGS_SHA256; -+ rctx->digsize = SHA3_256_DIGEST_SIZE; -+ rctx->blksize = SHA3_256_BLOCK_SIZE; ++ 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 SHA3_384_DIGEST_SIZE: -+ rctx->cmd |= SHA3_CMD_MODE_384; -+ rctx->flags |= SHA3_FLAGS_SHA384; -+ rctx->digsize = SHA3_384_DIGEST_SIZE; -+ rctx->blksize = SHA3_384_BLOCK_SIZE; ++ 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 SHA3_512_DIGEST_SIZE: -+ rctx->cmd |= SHA3_CMD_MODE_512; -+ rctx->flags |= SHA3_FLAGS_SHA512; -+ rctx->digsize = SHA3_512_DIGEST_SIZE; -+ rctx->blksize = SHA3_512_BLOCK_SIZE; ++ 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; -+ default: -+ dev_warn(tctx->rsss_dev->dev, "digest size %d not support\n", -+ crypto_ahash_digestsize(tfm)); -+ return -EINVAL; -+ } -+ -+ rctx->bufcnt = 0; -+ rctx->total = 0; -+ rctx->digcnt[0] = 0; -+ rctx->digcnt[1] = 0; -+ -+ memset(rctx->digest, 0x0, SHA3_512_DIGEST_SIZE); -+ -+ return aspeed_sha3_handle_queue(rsss_dev, req); -+} -+ -+static int aspeed_sha3_digest(struct ahash_request *req) -+{ -+ return aspeed_sha3_init(req) ? : aspeed_sha3_finup(req); -+} -+ -+static int aspeed_sha3_export(struct ahash_request *req, void *out) -+{ -+ struct aspeed_sha3_reqctx *rctx = ahash_request_ctx(req); -+ -+ memcpy(out, rctx, sizeof(*rctx)); -+ -+ return 0; -+} -+ -+static int aspeed_sha3_import(struct ahash_request *req, const void *in) -+{ -+ struct aspeed_sha3_reqctx *rctx = ahash_request_ctx(req); -+ -+ memcpy(rctx, in, sizeof(*rctx)); -+ -+ return 0; -+} -+ -+static int aspeed_sha3_cra_init(struct crypto_tfm *tfm) -+{ -+ struct ahash_alg *alg = __crypto_ahash_alg(tfm->__crt_alg); -+ struct aspeed_sha3_ctx *tctx = crypto_tfm_ctx(tfm); -+ struct aspeed_rsss_alg *ast_alg; -+ -+ ast_alg = container_of(alg, struct aspeed_rsss_alg, alg.ahash.base); -+ tctx->rsss_dev = ast_alg->rsss_dev; -+ -+ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), -+ sizeof(struct aspeed_sha3_reqctx)); -+ -+ return 0; -+} -+ -+static void aspeed_sha3_cra_exit(struct crypto_tfm *tfm) -+{ -+ struct aspeed_sha3_ctx *tctx = crypto_tfm_ctx(tfm); -+ struct aspeed_rsss_dev *rsss_dev = tctx->rsss_dev; -+ -+ RSSS_DBG(rsss_dev, "%s\n", crypto_tfm_alg_name(tfm)); -+} -+ -+struct aspeed_rsss_alg aspeed_rsss_algs_sha3_224 = { -+ .type = ASPEED_ALGO_TYPE_AHASH, -+ .alg.ahash.base = { -+ .init = aspeed_sha3_init, -+ .update = aspeed_sha3_update, -+ .final = aspeed_sha3_final, -+ .finup = aspeed_sha3_finup, -+ .digest = aspeed_sha3_digest, -+ .export = aspeed_sha3_export, -+ .import = aspeed_sha3_import, -+ .halg = { -+ .digestsize = SHA3_224_DIGEST_SIZE, -+ .statesize = sizeof(struct aspeed_sha3_reqctx), -+ .base = { -+ .cra_name = "sha3-224", -+ .cra_driver_name = "aspeed-sha3-224", -+ .cra_priority = 300, -+ .cra_flags = CRYPTO_ALG_TYPE_AHASH | -+ CRYPTO_ALG_ASYNC | -+ CRYPTO_ALG_KERN_DRIVER_ONLY, -+ .cra_blocksize = SHA3_224_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct aspeed_sha3_ctx), -+ .cra_module = THIS_MODULE, -+ .cra_init = aspeed_sha3_cra_init, -+ .cra_exit = aspeed_sha3_cra_exit, ++ 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); + } -+ }, -+ .alg.ahash.op = { -+ .do_one_request = aspeed_sha3_do_request, -+ }, -+}; -+ -+struct aspeed_rsss_alg aspeed_rsss_algs_sha3_256 = { -+ .type = ASPEED_ALGO_TYPE_AHASH, -+ .alg.ahash.base = { -+ .init = aspeed_sha3_init, -+ .update = aspeed_sha3_update, -+ .final = aspeed_sha3_final, -+ .finup = aspeed_sha3_finup, -+ .digest = aspeed_sha3_digest, -+ .export = aspeed_sha3_export, -+ .import = aspeed_sha3_import, -+ .halg = { -+ .digestsize = SHA3_256_DIGEST_SIZE, -+ .statesize = sizeof(struct aspeed_sha3_reqctx), -+ .base = { -+ .cra_name = "sha3-256", -+ .cra_driver_name = "aspeed-sha3-256", -+ .cra_priority = 300, -+ .cra_flags = CRYPTO_ALG_TYPE_AHASH | -+ CRYPTO_ALG_ASYNC | -+ CRYPTO_ALG_KERN_DRIVER_ONLY, -+ .cra_blocksize = SHA3_256_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct aspeed_sha3_ctx), -+ .cra_module = THIS_MODULE, -+ .cra_init = aspeed_sha3_cra_init, -+ .cra_exit = aspeed_sha3_cra_exit, ++ 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]); + } + } -+ }, -+ .alg.ahash.op = { -+ .do_one_request = aspeed_sha3_do_request, -+ }, -+}; -+ -+struct aspeed_rsss_alg aspeed_rsss_algs_sha3_384 = { -+ .type = ASPEED_ALGO_TYPE_AHASH, -+ .alg.ahash.base = { -+ .init = aspeed_sha3_init, -+ .update = aspeed_sha3_update, -+ .final = aspeed_sha3_final, -+ .finup = aspeed_sha3_finup, -+ .digest = aspeed_sha3_digest, -+ .export = aspeed_sha3_export, -+ .import = aspeed_sha3_import, -+ .halg = { -+ .digestsize = SHA3_384_DIGEST_SIZE, -+ .statesize = sizeof(struct aspeed_sha3_reqctx), -+ .base = { -+ .cra_name = "sha3-384", -+ .cra_driver_name = "aspeed-sha3-384", -+ .cra_priority = 300, -+ .cra_flags = CRYPTO_ALG_TYPE_AHASH | -+ CRYPTO_ALG_ASYNC | -+ CRYPTO_ALG_KERN_DRIVER_ONLY, -+ .cra_blocksize = SHA3_384_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct aspeed_sha3_ctx), -+ .cra_module = THIS_MODULE, -+ .cra_init = aspeed_sha3_cra_init, -+ .cra_exit = aspeed_sha3_cra_exit, ++ 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); + } -+ }, -+ .alg.ahash.op = { -+ .do_one_request = aspeed_sha3_do_request, -+ }, -+}; -+ -+struct aspeed_rsss_alg aspeed_rsss_algs_sha3_512 = { -+ .type = ASPEED_ALGO_TYPE_AHASH, -+ .alg.ahash.base = { -+ .init = aspeed_sha3_init, -+ .update = aspeed_sha3_update, -+ .final = aspeed_sha3_final, -+ .finup = aspeed_sha3_finup, -+ .digest = aspeed_sha3_digest, -+ .export = aspeed_sha3_export, -+ .import = aspeed_sha3_import, -+ .halg = { -+ .digestsize = SHA3_512_DIGEST_SIZE, -+ .statesize = sizeof(struct aspeed_sha3_reqctx), -+ .base = { -+ .cra_name = "sha3-512", -+ .cra_driver_name = "aspeed-sha3-512", -+ .cra_priority = 300, -+ .cra_flags = CRYPTO_ALG_TYPE_AHASH | -+ CRYPTO_ALG_ASYNC | -+ CRYPTO_ALG_KERN_DRIVER_ONLY, -+ .cra_blocksize = SHA3_512_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct aspeed_sha3_ctx), -+ .cra_module = THIS_MODULE, -+ .cra_init = aspeed_sha3_cra_init, -+ .cra_exit = aspeed_sha3_cra_exit, ++ 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]); + } + } -+ }, -+ .alg.ahash.op = { -+ .do_one_request = aspeed_sha3_do_request, -+ }, -+}; -+ -+static void aspeed_rsss_sha3_done_task(unsigned long data) -+{ -+ struct aspeed_rsss_dev *rsss_dev = (struct aspeed_rsss_dev *)data; -+ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; ++ 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]); ++ } ++ } ++ 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)); + -+ (void)sha3_engine->resume(rsss_dev); -+} ++ /* clear sirq log */ ++ while (readl(i2c_bus->reg_base + AST2700_I2CC_SIRQ_LOG)) ++ ; ++ break; ++ } + -+void aspeed_rsss_sha3_exit(struct aspeed_rsss_dev *rsss_dev) -+{ -+ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; ++ if (cmd) ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); + -+ crypto_engine_exit(rsss_dev->crypt_engine_sha3); -+ tasklet_kill(&sha3_engine->done_task); ++ writel(isr, i2c_bus->reg_base + AST2600_I2CS_ISR); ++ readl(i2c_bus->reg_base + AST2600_I2CS_ISR); +} + -+int aspeed_rsss_sha3_init(struct aspeed_rsss_dev *rsss_dev) ++static void ast2600_i2c_target_packet_dma_irq(struct ast2600_i2c_bus *i2c_bus, u32 sts) +{ -+ struct aspeed_engine_sha3 *sha3_engine; -+ u32 val; -+ int rc; -+ -+ rc = reset_control_deassert(rsss_dev->reset_sha3); -+ if (rc) { -+ dev_err(rsss_dev->dev, "Deassert SHA3 reset failed\n"); -+ goto end; -+ } -+ -+ sha3_engine = &rsss_dev->sha3_engine; -+ -+ /* Initialize crypto hardware engine structure for SHA3 */ -+ rsss_dev->crypt_engine_sha3 = crypto_engine_alloc_init(rsss_dev->dev, true); -+ if (!rsss_dev->crypt_engine_sha3) { -+ rc = -ENOMEM; -+ goto end; -+ } -+ -+ rc = crypto_engine_start(rsss_dev->crypt_engine_sha3); -+ if (rc) -+ goto err_engine_sha3_start; ++ int target_rx_len = 0; ++ u32 cmd = 0; ++ u8 value; ++ int i; + -+ tasklet_init(&sha3_engine->done_task, aspeed_rsss_sha3_done_task, -+ (unsigned long)rsss_dev); ++ sts &= ~(AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_SADDR_PENDING ++ | AST2600_I2CS_ADDR_NAK_MASK); + -+ /* Allocate DMA buffer for hash engine input used */ -+ sha3_engine->ahash_src_addr = -+ dmam_alloc_coherent(rsss_dev->dev, -+ ASPEED_HASH_SRC_DMA_BUF_LEN, -+ &sha3_engine->ahash_src_dma_addr, -+ GFP_KERNEL); -+ if (!sha3_engine->ahash_src_addr) { -+ dev_err(rsss_dev->dev, "Failed to allocate DMA src buffer\n"); -+ rc = -ENOMEM; -+ goto err_engine_sha3_start; -+ } ++ i2c_bus->target = i2c_bus->multi_target[AST2600_I2CS_GET_TARGET(sts)]; + -+ sha3_engine->buffer_addr = dmam_alloc_coherent(rsss_dev->dev, SHA3_224_BLOCK_SIZE, -+ &sha3_engine->buffer_dma_addr, -+ GFP_KERNEL); -+ if (!sha3_engine->buffer_addr) { -+ dev_err(rsss_dev->dev, "Failed to allocate DMA buffer\n"); -+ rc = -ENOMEM; -+ goto err_engine_sha3_start; -+ } ++ /* 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; + -+ sha3_engine->digest_addr = dmam_alloc_coherent(rsss_dev->dev, SHA3_512_DIGEST_SIZE, -+ &sha3_engine->digest_dma_addr, -+ GFP_KERNEL); -+ if (!sha3_engine->digest_addr) { -+ dev_err(rsss_dev->dev, "Failed to allocate DMA digest buffer\n"); -+ rc = -ENOMEM; -+ goto err_engine_sha3_start; ++ 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; + } + -+ /* -+ * Set 1 to use scatter-gather mode. -+ * Set 0 to use direct mode. -+ */ -+ sha3_engine->sg_mode = 0; -+ -+ /* Self-test */ -+ rc = aspeed_sha3_self_test(rsss_dev); -+ if (rc) -+ goto err_engine_sha3_start; -+ -+ /* Sha3 engine hardware init done, prepare queue lock */ -+ mutex_init(&sha3_engine->queue_lock); ++ sts &= ~(AST2600_I2CS_PKT_DONE | AST2600_I2CS_PKT_ERROR | AST2600_I2CS_ADDR_INDICATE_MASK); + -+ /* Enable SHA3 interrupt */ -+ val = ast_rsss_read(rsss_dev, ASPEED_RSSS_INT_EN); -+ ast_rsss_write(rsss_dev, val | SHA3_INT_EN, ASPEED_RSSS_INT_EN); -+ dev_info(rsss_dev->dev, "Aspeed RSSS SHA3 interrupt mode.\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]); ++ } ++ 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); + -+ dev_info(rsss_dev->dev, "Aspeed RSSS SHA3 initialized (%s mode)\n", -+ sha3_engine->sg_mode ? "SG" : "Direct"); ++ 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); ++ 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; + -+ return 0; ++ /* 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); + -+err_engine_sha3_start: -+ crypto_engine_exit(rsss_dev->crypt_engine_sha3); -+end: -+ return rc; -+} -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 2026-04-08 18:03:48.328704991 +0000 -@@ -0,0 +1,575 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright 2023 Aspeed Technology Inc. -+ */ ++ 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; ++ } + -+#include -+#include "aspeed-rsss.h" ++ if (cmd) ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); + -+static u8 data_rev[SRAM_BLOCK_SIZE]; -+static u8 data[SRAM_BLOCK_SIZE]; -+static int dbg; ++ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_ISR); ++ readl(i2c_bus->reg_base + AST2600_I2CS_ISR); ++} + -+static void hexdump(char *name, unsigned char *buf, unsigned int len) ++static void ast2600_i2c_target_packet_buff_irq(struct ast2600_i2c_bus *i2c_bus, u32 sts) +{ -+ if (!dbg) ++ int target_rx_len = 0; ++ u32 cmd = 0; ++ u8 value; ++ int i; ++ ++ /* 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); ++ } ++ ++ 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); ++ /* 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; ++ } + -+#ifdef CONFIG_CRYPTO_DEV_ASPEED_DEBUG -+ pr_info("%s:\n", name); -+ print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET, -+ 16, 1, buf, len, false); -+#endif -+} ++ sts &= ~(AST2600_I2CS_PKT_DONE | AST2600_I2CS_PKT_ERROR | AST2600_I2CS_ADDR_INDICATE_MASK); + -+static int aspeed_rsa_self_test(struct aspeed_rsss_dev *rsss_dev) -+{ -+ struct aspeed_engine_rsa *rsa_engine; -+ const u32 pattern = 0xffffffff; -+ u32 val; ++ if (sts & AST2600_I2CS_SLAVE_MATCH) ++ i2c_bus->target_operate = 1; + -+ rsa_engine = &rsss_dev->rsa_engine; ++ 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; + -+ /* Set SRAM access control - CPU */ -+ val = ast_rsss_read(rsss_dev, ASPEED_RSSS_CTRL); -+ ast_rsss_write(rsss_dev, val | SRAM_AHB_MODE_CPU, ASPEED_RSSS_CTRL); ++ 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); + -+ writel(pattern, rsa_engine->sram_exp); -+ val = readl(rsa_engine->sram_exp); -+ if (val != pattern) -+ return -EIO; ++ 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; ++ } + -+ writel(0x0, rsa_engine->sram_exp); ++ 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); + -+ return 0; ++ 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 inline struct akcipher_request * -+ akcipher_request_cast(struct crypto_async_request *req) ++static void ast2600_i2c_target_byte_irq(struct ast2600_i2c_bus *i2c_bus, u32 sts) +{ -+ return container_of(req, struct akcipher_request, base); -+} ++ u32 i2c_buff = readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF); ++ u32 cmd = AST2600_I2CS_ACTIVE_ALL; ++ u8 byte_data; ++ u8 value; + -+static int aspeed_rsa_do_fallback(struct akcipher_request *req) -+{ -+ struct crypto_akcipher *cipher = crypto_akcipher_reqtfm(req); -+ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(cipher); -+ int err; ++ i2c_bus->target = i2c_bus->multi_target[AST2600_I2CS_GET_TARGET(sts)]; + -+ akcipher_request_set_tfm(req, ctx->fallback_tfm); ++ /* 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; + -+ if (ctx->enc) -+ err = crypto_akcipher_encrypt(req); -+ else -+ err = crypto_akcipher_decrypt(req); ++ 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; ++ } + -+ akcipher_request_set_tfm(req, cipher); ++ sts &= ~(AST2600_I2CS_ADDR_INDICATE_MASK); + -+ return err; ++ 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); +} + -+static bool aspeed_rsa_need_fallback(struct akcipher_request *req) ++static int ast2600_i2c_target_irq(struct ast2600_i2c_bus *i2c_bus) +{ -+ struct crypto_akcipher *cipher = crypto_akcipher_reqtfm(req); -+ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(cipher); ++ u32 ier = readl(i2c_bus->reg_base + AST2600_I2CS_IER); ++ u32 isr = readl(i2c_bus->reg_base + AST2600_I2CS_ISR); + -+ return ctx->key.n_sz > ASPEED_RSA_MAX_KEY_LEN; -+} ++ if (!(isr & ier)) ++ return 0; + -+static int aspeed_rsa_handle_queue(struct aspeed_rsss_dev *rsss_dev, -+ struct akcipher_request *req) -+{ -+ if (aspeed_rsa_need_fallback(req)) { -+ RSSS_DBG(rsss_dev, "SW fallback\n"); -+ return aspeed_rsa_do_fallback(req); ++ /* ++ * 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; ++ ++ isr &= ~(AST2600_I2CS_ADDR_MASK); ++ ++ 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); + } + -+ return crypto_transfer_akcipher_request_to_engine(rsss_dev->crypt_engine_rsa, req); ++ return 1; +} ++#endif + -+static int aspeed_rsa_do_request(struct crypto_engine *engine, void *areq) ++static int ast2600_i2c_setup_dma_tx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) +{ -+ struct akcipher_request *req = akcipher_request_cast(areq); -+ struct crypto_akcipher *cipher = crypto_akcipher_reqtfm(req); -+ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(cipher); -+ struct aspeed_rsss_dev *rsss_dev = ctx->rsss_dev; -+ struct aspeed_engine_rsa *rsa_engine; ++ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; ++ int xfer_len = msg->len - i2c_bus->controller_xfer_cnt; ++ int ret; + -+ rsa_engine = &rsss_dev->rsa_engine; -+ rsa_engine->req = req; -+ rsa_engine->flags |= CRYPTO_FLAGS_BUSY; ++ cmd |= AST2600_I2CM_PKT_EN; + -+ return ctx->trigger(rsss_dev); -+} ++ 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; + -+static int aspeed_rsa_complete(struct aspeed_rsss_dev *rsss_dev, int err) -+{ -+ struct aspeed_engine_rsa *rsa_engine = &rsss_dev->rsa_engine; -+ struct akcipher_request *req = rsa_engine->req; ++ 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; ++ } ++ } ++ } + -+ rsa_engine->flags &= ~CRYPTO_FLAGS_BUSY; ++ 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); ++ } + -+ crypto_finalize_akcipher_request(rsss_dev->crypt_engine_rsa, req, err); ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); + -+ return err; ++ return 0; +} + -+/* -+ * Copy Data to SRAM buffer for engine used. -+ */ -+static void aspeed_rsa_sg_copy_to_buffer(struct aspeed_rsss_dev *rsss_dev, -+ void __iomem *buf, struct scatterlist *src, -+ size_t nbytes) ++static int ast2600_i2c_setup_buff_tx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) +{ -+ RSSS_DBG(rsss_dev, "src len:%zu\n", nbytes); ++ 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; + -+ memset(data_rev, 0, SRAM_BLOCK_SIZE); -+ memset(data, 0, SRAM_BLOCK_SIZE); ++ cmd |= AST2600_I2CM_PKT_EN; + -+ scatterwalk_map_and_copy(data, src, 0, nbytes, 0); ++ 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; + -+ hexdump("data", data, nbytes); -+ for (int i = 0; i < nbytes; i++) -+ data_rev[nbytes - i - 1] = data[i]; -+ -+ /* align 8 bytes */ -+ memcpy_toio(buf, data_rev, (nbytes + 7) & ~(8 - 1)); -+} -+ -+/* -+ * Copy Exp/Mod to SRAM buffer for engine used. -+ * -+ * Params: -+ * - mode 0 : Exponential -+ * - mode 1 : Modulus -+ */ -+static int aspeed_rsa_ctx_copy(struct aspeed_rsss_dev *rsss_dev, void __iomem *dst, -+ const u8 *src, size_t nbytes, -+ enum aspeed_rsa_key_mode mode) -+{ -+ RSSS_DBG(rsss_dev, "nbytes:%zu, mode:%d\n", nbytes, mode); -+ -+ if (nbytes > ASPEED_RSA_MAX_KEY_LEN) -+ return -ENOMEM; ++ if (cmd & AST2600_I2CM_START_CMD) ++ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); + -+ memset(data, 0, SRAM_BLOCK_SIZE); ++ 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; + -+ /* Remove leading zeros */ -+ while (nbytes > 0 && src[0] == 0) { -+ src++; -+ nbytes--; ++ 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); + } + -+ for (int i = 0; i < nbytes; i++) -+ data[nbytes - i - 1] = src[i]; ++ if (readl(i2c_bus->reg_base + AST2600_I2CS_ISR)) ++ return -ENOMEM; + -+ /* align 8 bytes */ -+ memcpy_toio(dst, data, (nbytes + 7) & ~(8 - 1)); ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); + -+ return nbytes * 8; ++ return 0; +} + -+static int aspeed_rsa_transfer(struct aspeed_rsss_dev *rsss_dev) ++static int ast2600_i2c_setup_byte_tx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) +{ -+ struct aspeed_engine_rsa *rsa_engine = &rsss_dev->rsa_engine; -+ struct akcipher_request *req = rsa_engine->req; -+ struct scatterlist *out_sg = req->dst; -+ size_t nbytes = req->dst_len; -+ u8 data[SRAM_BLOCK_SIZE]; -+ u32 val; ++ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; ++ int xfer_len; + -+ RSSS_DBG(rsss_dev, "nbytes:%zu\n", nbytes); ++ xfer_len = msg->len - i2c_bus->controller_xfer_cnt; + -+ /* Set SRAM access control - CPU */ -+ val = ast_rsss_read(rsss_dev, ASPEED_RSSS_CTRL); -+ ast_rsss_write(rsss_dev, val | SRAM_AHB_MODE_CPU, ASPEED_RSSS_CTRL); ++ cmd |= AST2600_I2CM_PKT_EN; + -+ for (int i = 0; i < nbytes; i++) -+ data[nbytes - i - 1] = readb(rsa_engine->sram_data + i); ++ if (cmd & AST2600_I2CM_START_CMD) ++ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); + -+ scatterwalk_map_and_copy(data, out_sg, 0, nbytes, 1); ++ if ((i2c_bus->msgs_index + 1 == i2c_bus->msgs_count) && ++ xfer_len == 1) ++ cmd |= AST2600_I2CM_STOP_CMD; + -+ return aspeed_rsa_complete(rsss_dev, 0); ++ 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); ++ } ++ ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); ++ ++ return 0; +} + -+#ifdef RSSS_RSA_POLLING_MODE -+static int aspeed_rsa_wait_complete(struct aspeed_rsss_dev *rsss_dev) ++static int ast2600_i2c_setup_dma_rx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) +{ -+ struct aspeed_engine_rsa *rsa_engine = &rsss_dev->rsa_engine; -+ u32 sts; ++ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; ++ int xfer_len = msg->len - i2c_bus->controller_xfer_cnt; + int ret; + -+ ret = readl_poll_timeout(rsss_dev->regs + ASPEED_RSA_ENG_STS, sts, -+ ((sts & RSA_STS) == 0x0), -+ ASPEED_RSSS_POLLING_TIME, -+ ASPEED_RSSS_TIMEOUT * 10); -+ if (ret) { -+ dev_err(rsss_dev->dev, "RSA wrong engine status\n"); -+ return -EIO; -+ } ++ cmd |= AST2600_I2CM_PKT_EN | AST2600_I2CM_RX_DMA_EN | AST2600_I2CM_RX_CMD; + -+ ret = readl_poll_timeout(rsss_dev->regs + ASPEED_RSSS_INT_STS, sts, -+ ((sts & RSA_INT_DONE) == RSA_INT_DONE), -+ ASPEED_RSSS_POLLING_TIME, -+ ASPEED_RSSS_TIMEOUT); -+ if (ret) { -+ dev_err(rsss_dev->dev, "RSA wrong interrupt status\n"); -+ return -EIO; ++ 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; + } + -+ ast_rsss_write(rsss_dev, sts, ASPEED_RSSS_INT_STS); -+ -+ RSSS_DBG(rsss_dev, "irq sts:0x%x\n", sts); -+ -+ if (sts & RSA_INT_DONE) { -+ /* Stop RSA engine */ -+ ast_rsss_write(rsss_dev, 0, ASPEED_RSA_TRIGGER); ++ writel(AST2600_I2CM_SET_RX_DMA_LEN(xfer_len - 1), i2c_bus->reg_base + AST2600_I2CM_DMA_LEN); + -+ if (rsa_engine->flags & CRYPTO_FLAGS_BUSY) -+ tasklet_schedule(&rsa_engine->done_task); ++ 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 -+ dev_err(rsss_dev->dev, "RSA no active requests.\n"); ++ 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); ++ + return 0; +} -+#endif + -+static int aspeed_rsa_trigger(struct aspeed_rsss_dev *rsss_dev) ++static int ast2600_i2c_setup_buff_rx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) +{ -+ struct aspeed_engine_rsa *rsa_engine = &rsss_dev->rsa_engine; -+ struct akcipher_request *req = rsa_engine->req; -+ struct crypto_akcipher *cipher; -+ struct aspeed_rsa_ctx *ctx; -+ int ne, nm; -+ u32 val; -+ -+ RSSS_DBG(rsss_dev, "\n"); -+ -+ cipher = crypto_akcipher_reqtfm(req); -+ ctx = akcipher_tfm_ctx(cipher); -+ -+ if (!ctx->n_sz) { -+ dev_err(rsss_dev->dev, "%s: key n is not set\n", __func__); -+ return -EINVAL; -+ } -+ -+ /* Set SRAM access control - CPU */ -+ val = ast_rsss_read(rsss_dev, ASPEED_RSSS_CTRL); -+ ast_rsss_write(rsss_dev, val | SRAM_AHB_MODE_CPU, ASPEED_RSSS_CTRL); -+ -+ memset_io(rsa_engine->sram_exp, 0, SRAM_BLOCK_SIZE); -+ memset_io(rsa_engine->sram_mod, 0, SRAM_BLOCK_SIZE); -+ memset_io(rsa_engine->sram_data, 0, SRAM_BLOCK_SIZE); -+ -+ /* Copy source data to SRAM buffer */ -+ aspeed_rsa_sg_copy_to_buffer(rsss_dev, rsa_engine->sram_data, -+ req->src, req->src_len); ++ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; ++ int xfer_len = msg->len - i2c_bus->controller_xfer_cnt; + -+ nm = aspeed_rsa_ctx_copy(rsss_dev, rsa_engine->sram_mod, ctx->n, -+ ctx->n_sz, ASPEED_RSA_MOD_MODE); ++ cmd |= AST2600_I2CM_PKT_EN | AST2600_I2CM_RX_BUFF_EN | AST2600_I2CM_RX_CMD; + -+ /* Set dst len as modulus size */ -+ req->dst_len = nm / 8; ++ if (cmd & AST2600_I2CM_START_CMD) ++ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); + -+ if (ctx->enc) { -+ if (!ctx->e_sz) { -+ dev_err(rsss_dev->dev, "%s: key e is not set\n", -+ __func__); -+ return -EINVAL; -+ } -+ /* Copy key e to SRAM buffer */ -+ ne = aspeed_rsa_ctx_copy(rsss_dev, rsa_engine->sram_exp, -+ ctx->e, ctx->e_sz, -+ ASPEED_RSA_EXP_MODE); -+ } else { -+ if (!ctx->d_sz) { -+ dev_err(rsss_dev->dev, "%s: key d is not set\n", -+ __func__); -+ return -EINVAL; -+ } -+ /* Copy key d to SRAM buffer */ -+ ne = aspeed_rsa_ctx_copy(rsss_dev, rsa_engine->sram_exp, -+ ctx->key.d, ctx->key.d_sz, -+ ASPEED_RSA_EXP_MODE); ++ 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; + } + -+ hexdump("exp", rsa_engine->sram_exp, ctx->e_sz); -+ hexdump("mod", rsa_engine->sram_mod, ctx->n_sz); -+ hexdump("data", rsa_engine->sram_data, req->src_len); -+ -+ rsa_engine->resume = aspeed_rsa_transfer; -+ -+ ast_rsss_write(rsss_dev, (ne << 16) + nm, -+ ASPEED_RSA_KEY_INFO); -+ -+ /* Set SRAM access control - Engine */ -+ val = ast_rsss_read(rsss_dev, ASPEED_RSSS_CTRL); -+ ast_rsss_write(rsss_dev, val & ~SRAM_AHB_MODE_CPU, ASPEED_RSSS_CTRL); ++ writel(AST2600_I2CC_SET_RX_BUF_LEN(xfer_len), i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); + -+ /* Trigger RSA engines */ -+ ast_rsss_write(rsss_dev, RSA_TRIGGER, ASPEED_RSA_TRIGGER); ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); + -+#ifdef RSSS_RSA_POLLING_MODE -+ return aspeed_rsa_wait_complete(rsss_dev); -+#else + return 0; -+#endif +} + -+static int aspeed_rsa_enc(struct akcipher_request *req) ++static int ast2600_i2c_setup_byte_rx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) +{ -+ struct crypto_akcipher *cipher = crypto_akcipher_reqtfm(req); -+ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(cipher); -+ struct aspeed_rsss_dev *rsss_dev = ctx->rsss_dev; ++ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; + -+ ctx->trigger = aspeed_rsa_trigger; -+ ctx->enc = 1; ++ cmd |= AST2600_I2CM_PKT_EN | AST2600_I2CM_RX_CMD; + -+ return aspeed_rsa_handle_queue(rsss_dev, req); -+} ++ if (cmd & AST2600_I2CM_START_CMD) ++ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); + -+static int aspeed_rsa_dec(struct akcipher_request *req) -+{ -+ struct crypto_akcipher *cipher = crypto_akcipher_reqtfm(req); -+ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(cipher); -+ struct aspeed_rsss_dev *rsss_dev = ctx->rsss_dev; ++ 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; ++ } + -+ ctx->trigger = aspeed_rsa_trigger; -+ ctx->enc = 0; ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); + -+ return aspeed_rsa_handle_queue(rsss_dev, req); ++ return 0; +} + -+static int aspeed_rsa_set_n(struct aspeed_rsa_ctx *ctx, u8 *value, -+ size_t len) ++static int ast2600_i2c_do_start(struct ast2600_i2c_bus *i2c_bus) +{ -+ ctx->n_sz = len; -+ memcpy(ctx->n, value, len); ++ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; + -+ return 0; ++ /* 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); ++ ++ i2c_bus->controller_xfer_cnt = 0; ++ i2c_bus->buf_index = 0; ++ ++ 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); ++ } +} + -+static int aspeed_rsa_set_e(struct aspeed_rsa_ctx *ctx, u8 *value, -+ size_t len) ++static int ast2700_i2c_irq_err_to_errno(u32 irq_status) +{ -+ ctx->e_sz = len; -+ memcpy(ctx->e, value, len); ++ 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 int aspeed_rsa_set_d(struct aspeed_rsa_ctx *ctx, u8 *value, -+ size_t len) ++static int ast2600_i2c_irq_err_to_errno(u32 irq_status) +{ -+ ctx->d_sz = len; -+ memcpy(ctx->d, value, len); ++ 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; + + return 0; +} + -+static int aspeed_rsa_setkey(struct crypto_akcipher *tfm, const void *key, -+ unsigned int keylen, int priv) ++static void ast2600_i2c_controller_package_irq(struct ast2600_i2c_bus *i2c_bus, u32 sts) +{ -+ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); -+ struct aspeed_rsss_dev *rsss_dev = ctx->rsss_dev; -+ int ret; -+ -+ RSSS_DBG(rsss_dev, "\n"); ++ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; ++ int xfer_len; ++ int i; + -+ if (priv) -+ ret = rsa_parse_priv_key(&ctx->key, key, keylen); ++ if (i2c_bus->version == AST2700) ++ writel(sts, i2c_bus->reg_base + AST2600_I2CM_ISR); + else -+ ret = rsa_parse_pub_key(&ctx->key, key, keylen); -+ -+ if (ret) { -+ dev_err(rsss_dev->dev, "rsss parse key failed, ret:0x%x\n", -+ ret); -+ return ret; -+ } -+ -+ /* Aspeed engine supports up to 4096 bits, -+ * Use software fallback instead. -+ */ -+ if (ctx->key.n_sz > ASPEED_RSA_MAX_KEY_LEN) -+ return 0; ++ writel(AST2600_I2CM_PKT_DONE, i2c_bus->reg_base + AST2600_I2CM_ISR); + -+ hexdump("n", (u8 *)ctx->key.n, ctx->key.n_sz); -+ aspeed_rsa_set_n(ctx, (u8 *)ctx->key.n, ctx->key.n_sz); ++ sts &= ~(AST2600_I2CM_PKT_DONE | AST2600_I2CM_SW_ISR_MASK); + -+ hexdump("e", (u8 *)ctx->key.e, ctx->key.e_sz); -+ aspeed_rsa_set_e(ctx, (u8 *)ctx->key.e, ctx->key.e_sz); ++ 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)); ++ else ++ xfer_len = 1; + -+ if (priv) { -+ hexdump("d", (u8 *)ctx->key.d, ctx->key.d_sz); -+ aspeed_rsa_set_d(ctx, (u8 *)ctx->key.d, ctx->key.d_sz); -+ } ++ i2c_bus->controller_xfer_cnt += xfer_len; + -+ return 0; -+} ++ 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); + -+static int aspeed_rsa_set_pub_key(struct crypto_akcipher *tfm, -+ const void *key, -+ unsigned int keylen) -+{ -+ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); -+ int ret; ++ 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)); ++ } + -+ ret = crypto_akcipher_set_pub_key(ctx->fallback_tfm, key, keylen); -+ if (ret) -+ return ret; ++ if (msg->flags & I2C_M_RECV_LEN) { ++ u8 recv_len = 0; + -+ return aspeed_rsa_setkey(tfm, key, keylen, 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)); ++ } + -+static int aspeed_rsa_set_priv_key(struct crypto_akcipher *tfm, -+ const void *key, -+ unsigned int keylen) -+{ -+ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); -+ int ret; ++ 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; ++ } + -+ ret = crypto_akcipher_set_priv_key(ctx->fallback_tfm, key, keylen); -+ if (ret) -+ return ret; ++ 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; ++ } + -+ return aspeed_rsa_setkey(tfm, key, keylen, 1); ++ 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; ++ } +} + -+static unsigned int aspeed_rsa_max_size(struct crypto_akcipher *tfm) ++static int ast2600_i2c_controller_irq(struct ast2600_i2c_bus *i2c_bus) +{ -+ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); -+ -+ if (ctx->key.n_sz > ASPEED_RSA_MAX_KEY_LEN) -+ return crypto_akcipher_maxsize(ctx->fallback_tfm); ++ u32 sts = readl(i2c_bus->reg_base + AST2600_I2CM_ISR); ++ u32 ier = readl(i2c_bus->reg_base + AST2600_I2CM_IER); ++ u32 ctrl; + -+ return ctx->n_sz; -+} ++ /* mask un-used isr bits */ ++ sts &= ~AST2600_I2CM_ISR_MASK; + -+static int aspeed_rsa_init_tfm(struct crypto_akcipher *tfm) -+{ -+ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); -+ struct akcipher_alg *alg = crypto_akcipher_alg(tfm); -+ const char *name = crypto_tfm_alg_name(&tfm->base); -+ struct aspeed_rsss_alg *rsa_alg; ++ if (!i2c_bus->alert_enable) ++ sts &= ~AST2600_I2CM_SMBUS_ALT; + -+ rsa_alg = container_of(alg, struct aspeed_rsss_alg, alg.akcipher.base); ++ 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; ++ } + -+ ctx->rsss_dev = rsa_alg->rsss_dev; ++ 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; ++ } + -+ ctx->fallback_tfm = crypto_alloc_akcipher(name, 0, CRYPTO_ALG_ASYNC | -+ CRYPTO_ALG_NEED_FALLBACK); -+ if (IS_ERR(ctx->fallback_tfm)) { -+ dev_err(ctx->rsss_dev->dev, "ERROR: Cannot allocate fallback for %s %ld\n", -+ name, PTR_ERR(ctx->fallback_tfm)); -+ return PTR_ERR(ctx->fallback_tfm); ++ 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; ++ } + } + -+ return 0; -+} ++ /* 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; ++ } ++ } + -+static void aspeed_rsa_exit_tfm(struct crypto_akcipher *tfm) -+{ -+ struct aspeed_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); ++ if (AST2600_I2CM_PKT_DONE & sts) { ++ ast2600_i2c_controller_package_irq(i2c_bus, sts); ++ return 1; ++ } + -+ crypto_free_akcipher(ctx->fallback_tfm); ++ return 0; +} + -+struct aspeed_rsss_alg aspeed_rsss_algs_rsa = { -+ .type = ASPEED_ALGO_TYPE_AKCIPHER, -+ .alg.akcipher.base = { -+ .encrypt = aspeed_rsa_enc, -+ .decrypt = aspeed_rsa_dec, -+ .sign = aspeed_rsa_dec, -+ .verify = aspeed_rsa_enc, -+ .set_pub_key = aspeed_rsa_set_pub_key, -+ .set_priv_key = aspeed_rsa_set_priv_key, -+ .max_size = aspeed_rsa_max_size, -+ .init = aspeed_rsa_init_tfm, -+ .exit = aspeed_rsa_exit_tfm, -+ .base = { -+ .cra_name = "rsa", -+ .cra_driver_name = "aspeed-rsa", -+ .cra_priority = 300, -+ .cra_flags = CRYPTO_ALG_TYPE_AKCIPHER | -+ CRYPTO_ALG_ASYNC | -+ CRYPTO_ALG_KERN_DRIVER_ONLY | -+ CRYPTO_ALG_NEED_FALLBACK, -+ .cra_module = THIS_MODULE, -+ .cra_ctxsize = sizeof(struct aspeed_rsa_ctx), -+ }, -+ }, -+ .alg.akcipher.op = { -+ .do_one_request = aspeed_rsa_do_request, -+ }, -+}; -+ -+static void aspeed_rsa_done_task(unsigned long data) ++static irqreturn_t ast2600_i2c_bus_irq(int irq, void *dev_id) +{ -+ struct aspeed_rsss_dev *rsss_dev = (struct aspeed_rsss_dev *)data; -+ struct aspeed_engine_rsa *rsa_engine = &rsss_dev->rsa_engine; ++ struct ast2600_i2c_bus *i2c_bus = dev_id; + -+ (void)rsa_engine->resume(rsss_dev); ++#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)); +} + -+void aspeed_rsss_rsa_exit(struct aspeed_rsss_dev *rsss_dev) ++static int ast2600_i2c_controller_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ -+ struct aspeed_engine_rsa *rsa_engine = &rsss_dev->rsa_engine; -+ -+ crypto_engine_exit(rsss_dev->crypt_engine_rsa); -+ tasklet_kill(&rsa_engine->done_task); -+} ++ struct ast2600_i2c_bus *i2c_bus = i2c_get_adapdata(adap); ++ unsigned long timeout; ++ int ret; + -+int aspeed_rsss_rsa_init(struct aspeed_rsss_dev *rsss_dev) -+{ -+ struct aspeed_engine_rsa *rsa_engine; -+ u32 val; -+ int rc; ++ 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; ++ } + -+ rc = reset_control_deassert(rsss_dev->reset_rsa); -+ if (rc) { -+ dev_err(rsss_dev->dev, "Deassert RSA reset failed\n"); -+ goto end; ++#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 + -+ rsa_engine = &rsss_dev->rsa_engine; ++ 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); + -+ /* Initialize crypto hardware engine structure for RSA */ -+ rsss_dev->crypt_engine_rsa = crypto_engine_alloc_init(rsss_dev->dev, true); -+ if (!rsss_dev->crypt_engine_rsa) { -+ rc = -ENOMEM; -+ goto end; ++ 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); ++ } ++#endif ++ ret = -ETIMEDOUT; ++ } else { ++ ret = i2c_bus->cmd_err; + } + -+ rc = crypto_engine_start(rsss_dev->crypt_engine_rsa); -+ if (rc) -+ goto err_engine_rsa_start; ++ dev_dbg(i2c_bus->dev, "bus%d-m: %d end\n", i2c_bus->adap.nr, i2c_bus->cmd_err); + -+ tasklet_init(&rsa_engine->done_task, aspeed_rsa_done_task, -+ (unsigned long)rsss_dev); ++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]; + -+ rsa_engine->sram_exp = rsss_dev->regs + SRAM_OFFSET_EXP; -+ rsa_engine->sram_mod = rsss_dev->regs + SRAM_OFFSET_MOD; -+ rsa_engine->sram_data = rsss_dev->regs + SRAM_OFFSET_DATA; ++ 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; ++ } ++ } + -+ /* Set SRAM for RSA operation */ -+ ast_rsss_write(rsss_dev, RSA_OPERATION, ASPEED_RSSS_CTRL); ++ return ret; ++} + -+ /* Self-test */ -+ rc = aspeed_rsa_self_test(rsss_dev); -+ if (rc) -+ goto err_engine_rsa_start; ++static void 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; + -+ /* Enable RSA interrupt */ -+ val = ast_rsss_read(rsss_dev, ASPEED_RSSS_INT_EN); -+ ast_rsss_write(rsss_dev, val | RSA_INT_EN, ASPEED_RSSS_INT_EN); ++ /* I2C Reset */ ++ writel(0, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); + -+ dev_info(rsss_dev->dev, "Aspeed RSSS RSA initialized\n"); ++ i2c_bus->multi_master = device_property_read_bool(&pdev->dev, "multi-master"); ++ if (!i2c_bus->multi_master) ++ fun_ctrl |= AST2600_I2CC_MULTI_MASTER_DIS; + -+ return 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; + -+err_engine_rsa_start: -+ crypto_engine_exit(rsss_dev->crypt_engine_rsa); -+end: -+ return rc; -+} -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 2026-04-08 18:03:48.328704991 +0000 -@@ -0,0 +1,188 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright 2023 Aspeed Technology Inc. -+ */ ++ /* 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; ++ } + -+#include -+#include -+#include -+#include -+#include "aspeed-rsss.h" ++ debounce_level = readl(i2c_bus->reg_base + MSIC2_CONFIG) ++ & ~(AST2700_DEBOUNCE_MASK); + -+static struct aspeed_rsss_alg *aspeed_rsss_algs[] = { -+ &aspeed_rsss_algs_rsa, -+ &aspeed_rsss_algs_sha3_224, -+ &aspeed_rsss_algs_sha3_256, -+ &aspeed_rsss_algs_sha3_384, -+ &aspeed_rsss_algs_sha3_512, -+}; ++ debounce_level |= i2c_bus->debounce_level; ++ writel(debounce_level, i2c_bus->reg_base + MSIC2_CONFIG); + -+static void aspeed_rsss_register(struct aspeed_rsss_dev *rsss_dev) -+{ -+ char *cra_name; -+ int rc; ++ fun_ctrl |= AST2700_I2CC_MANUAL_DEBOUNCE; ++ } ++ } + -+ for (int i = 0; i < ARRAY_SIZE(aspeed_rsss_algs); i++) { -+ aspeed_rsss_algs[i]->rsss_dev = rsss_dev; -+ if (aspeed_rsss_algs[i]->type == ASPEED_ALGO_TYPE_AKCIPHER) { -+ rc = crypto_engine_register_akcipher(&aspeed_rsss_algs[i]->alg.akcipher); -+ cra_name = aspeed_rsss_algs[i]->alg.akcipher.base.base.cra_name; ++ /* 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); + -+ } else if (aspeed_rsss_algs[i]->type == ASPEED_ALGO_TYPE_AHASH) { -+ rc = crypto_engine_register_ahash(&aspeed_rsss_algs[i]->alg.ahash); -+ cra_name = aspeed_rsss_algs[i]->alg.ahash.base.halg.base.cra_name; -+ } ++ /* Set AC Timing */ ++ if (i2c_bus->version == AST2700) ++ ast2700_i2c_ac_timing_config(i2c_bus); ++ else ++ ast2600_i2c_ac_timing_config(i2c_bus); + -+ if (rc) -+ dev_warn(rsss_dev->dev, "Failed to register [%d] %s(0x%x)\n", i, cra_name, rc); ++ /* Clear Interrupt */ ++ writel(GENMASK(27, 0), i2c_bus->reg_base + AST2600_I2CM_ISR); ++ ++#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; + } -+} + -+static void aspeed_rsss_unregister(struct aspeed_rsss_dev *rsss_dev) -+{ -+ for (int i = 0; i < ARRAY_SIZE(aspeed_rsss_algs); i++) { -+ if (aspeed_rsss_algs[i]->type == ASPEED_ALGO_TYPE_AKCIPHER) -+ crypto_engine_unregister_akcipher(&aspeed_rsss_algs[i]->alg.akcipher); ++ writel(GENMASK(27, 0), i2c_bus->reg_base + AST2600_I2CS_ISR); + -+ else if (aspeed_rsss_algs[i]->type == ASPEED_ALGO_TYPE_AHASH) -+ crypto_engine_unregister_ahash(&aspeed_rsss_algs[i]->alg.ahash); -+ } ++ 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 +} + -+/* RSSS interrupt service routine. */ -+static irqreturn_t aspeed_rsss_irq(int irq, void *dev) ++#if IS_ENABLED(CONFIG_I2C_SLAVE) ++static int ast2600_i2c_reg_target(struct i2c_client *client) +{ -+ struct aspeed_rsss_dev *rsss_dev = (struct aspeed_rsss_dev *)dev; -+ struct aspeed_engine_sha3 *sha3_engine = &rsss_dev->sha3_engine; -+ struct aspeed_engine_rsa *rsa_engine = &rsss_dev->rsa_engine; -+ u32 sts; ++ 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; + -+ sts = ast_rsss_read(rsss_dev, ASPEED_RSSS_INT_STS); -+ ast_rsss_write(rsss_dev, sts, ASPEED_RSSS_INT_STS); ++ /* check target client input and target counts*/ ++ if (!client || i2c_bus->target_attached == AST2600_I2C_TARGET_COUNT) ++ return -EINVAL; + -+ RSSS_DBG(rsss_dev, "irq sts:0x%x\n", sts); ++ /* 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; ++ } ++ } ++ } + -+ if (sts & RSA_INT_DONE) { -+ /* Stop RSA engine */ -+ ast_rsss_write(rsss_dev, 0, ASPEED_RSA_TRIGGER); ++ /* 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); + -+ if (rsa_engine->flags & CRYPTO_FLAGS_BUSY) -+ tasklet_schedule(&rsa_engine->done_task); -+ else -+ dev_err(rsss_dev->dev, "RSA no active requests.\n"); -+ } ++ /* 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 & SHA3_INT_DONE) { -+ if (sha3_engine->flags & CRYPTO_FLAGS_BUSY) -+ tasklet_schedule(&sha3_engine->done_task); -+ else -+ dev_err(rsss_dev->dev, "SHA3 no active requests.\n"); ++ /* Set target addr. */ ++ writel(target_addr, i2c_bus->reg_base + AST2600_I2CS_ADDR_CTRL); ++ break; ++ } + } + -+ return IRQ_HANDLED; -+} -+ -+static const struct of_device_id aspeed_rsss_of_matches[] = { -+ { .compatible = "aspeed,ast2700-rsss", }, -+ {}, -+}; ++ /* don't reg target */ ++ if (!target_reg) ++ return -EINVAL; + -+static int aspeed_rsss_probe(struct platform_device *pdev) -+{ -+ struct aspeed_rsss_dev *rsss_dev; -+ struct device *dev = &pdev->dev; -+ int rc; ++ dev_dbg(i2c_bus->dev, "target addr %x\n", client->addr); + -+ rsss_dev = devm_kzalloc(dev, sizeof(struct aspeed_rsss_dev), -+ GFP_KERNEL); -+ if (!rsss_dev) -+ return -ENOMEM; ++ /* turn on target mode */ ++ if (!(ctrl & AST2600_I2CC_SLAVE_EN)) { ++ writel(ctrl | AST2600_I2CC_SLAVE_EN, ++ i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); ++ } + -+ rsss_dev->dev = dev; ++ /* 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; ++ } else { ++ cmd &= ~AST2600_I2CS_PKT_MODE_EN; ++ } + -+ platform_set_drvdata(pdev, rsss_dev); ++ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); + -+ rsss_dev->regs = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(rsss_dev->regs)) -+ return PTR_ERR(rsss_dev->regs); ++ i2c_bus->target_attached++; ++ return 0; ++} + -+ /* Get irq number and register it */ -+ rsss_dev->irq = platform_get_irq(pdev, 0); -+ if (rsss_dev->irq < 0) -+ return -ENXIO; ++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; + -+ rc = devm_request_irq(dev, rsss_dev->irq, aspeed_rsss_irq, 0, -+ dev_name(dev), rsss_dev); -+ if (rc) { -+ dev_err(dev, "Failed to request irq.\n"); -+ return rc; -+ } ++ /* check target client input and salve counts*/ ++ if (!client || i2c_bus->target_attached == 0) ++ return -EINVAL; + -+ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); -+ if (rc) { -+ dev_warn(&pdev->dev, "No suitable DMA available\n"); -+ return rc; -+ } ++ /* 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); + -+ rsss_dev->clk = devm_clk_get_enabled(dev, NULL); -+ if (IS_ERR(rsss_dev->clk)) { -+ dev_err(dev, "Failed to get rsss clk\n"); -+ return PTR_ERR(rsss_dev->clk); -+ } ++ /* 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; ++ } + -+ rsss_dev->reset_rsa = devm_reset_control_get(dev, "rsa"); -+ if (IS_ERR(rsss_dev->reset_rsa)) { -+ dev_err(dev, "Failed to get rsa reset\n"); -+ return PTR_ERR(rsss_dev->reset_rsa); ++ writel(target_addr, i2c_bus->reg_base + AST2600_I2CS_ADDR_CTRL); ++ break; ++ } ++ } + } + -+ rsss_dev->reset_sha3 = devm_reset_control_get(dev, "sha3"); -+ if (IS_ERR(rsss_dev->reset_sha3)) { -+ dev_err(dev, "Failed to get sha3 reset\n"); -+ return PTR_ERR(rsss_dev->reset_sha3); -+ } ++ /* don't un-reg target */ ++ if (!target_unreg) ++ return -EINVAL; + -+ rc = aspeed_rsss_rsa_init(rsss_dev); -+ if (rc) { -+ dev_err(dev, "RSA init failed\n"); -+ return rc; -+ } ++ i2c_bus->target_attached--; + -+ rc = aspeed_rsss_sha3_init(rsss_dev); -+ if (rc) { -+ dev_err(dev, "SHA3 init failed\n"); -+ return rc; ++ /* 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); + } + -+ aspeed_rsss_register(rsss_dev); -+ -+ dev_info(dev, "Aspeed RSSS Hardware Accelerator successfully registered\n"); -+ + return 0; +} ++#endif + -+static void aspeed_rsss_remove(struct platform_device *pdev) ++static u32 ast2600_i2c_functionality(struct i2c_adapter *adap) +{ -+ struct aspeed_rsss_dev *rsss_dev = platform_get_drvdata(pdev); -+ -+ aspeed_rsss_unregister(rsss_dev); -+ aspeed_rsss_rsa_exit(rsss_dev); -+ aspeed_rsss_sha3_exit(rsss_dev); ++ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA; +} + -+MODULE_DEVICE_TABLE(of, aspeed_rsss_of_matches); -+ -+static struct platform_driver aspeed_rsss_driver = { -+ .probe = aspeed_rsss_probe, -+ .remove = aspeed_rsss_remove, -+ .driver = { -+ .name = KBUILD_MODNAME, -+ .of_match_table = aspeed_rsss_of_matches, -+ }, ++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 +}; + -+module_platform_driver(aspeed_rsss_driver); ++static int ast2600_i2c_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct ast2600_i2c_bus *i2c_bus; ++ const char *xfer_mode; ++ struct resource *res; ++ u32 global_ctrl; ++ int ret; + -+MODULE_AUTHOR("Neal Liu "); -+MODULE_DESCRIPTION("ASPEED RSSS driver for multiple cryptographic engines"); -+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 2026-04-08 18:03:48.328704991 +0000 -@@ -0,0 +1,275 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ ++ i2c_bus = devm_kzalloc(dev, sizeof(*i2c_bus), GFP_KERNEL); ++ if (!i2c_bus) ++ return -ENOMEM; + -+#ifndef __ASPEED_RSSS_H__ -+#define __ASPEED_RSSS_H__ ++ i2c_bus->version = (enum i2c_version)device_get_match_data(dev); + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++ i2c_bus->reg_base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(i2c_bus->reg_base)) ++ return PTR_ERR(i2c_bus->reg_base); + -+#ifdef CONFIG_CRYPTO_DEV_ASPEED_DEBUG -+#define RSSS_DBG(d, fmt, ...) \ -+ dev_info((d)->dev, "%s() " fmt, __func__, ##__VA_ARGS__) -+#else -+#define RSSS_DBG(d, fmt, ...) \ -+ dev_dbg((d)->dev, "%s() " fmt, __func__, ##__VA_ARGS__) -+#endif ++ 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"); + -+/***************************** -+ * * -+ * RSSS register definitions * -+ * * -+ * ***************************/ -+#define ASPEED_RSSS_INT_STS 0xc00 /* RSSS interrupt status */ -+#define ASPEED_RSSS_INT_EN 0xc04 /* RSSS interrupt enable */ -+#define ASPEED_RSSS_CTRL 0xc08 /* RSSS generic control */ -+#define ASPEED_RSA_TRIGGER 0xe00 /* RSA Engine Control: trigger */ -+#define ASPEED_RSA_KEY_INFO 0xe08 /* RSA Exp/Mod Key Length (Bits) */ -+#define ASPEED_RSA_ENG_STS 0xe0c /* RSA Engine Status */ ++ reset_control_deassert(i2c_bus->rst); + -+#define ASPEED_SHA3_CMD 0xe80 -+#define ASPEED_SHA3_SRC_LO 0xe84 -+#define ASPEED_SHA3_SRC_HI 0xe88 -+#define ASPEED_SHA3_SRC_LEN 0xe8c -+#define ASPEED_SHA3_DST_LO 0xe90 -+#define ASPEED_SHA3_DST_HI 0xe94 -+#define ASPEED_SHA3_BUSY_STS 0xe98 -+#define ASPEED_SHA3_ENG_STS 0xe9c ++ 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); + -+/* RSSS interrupt status */ -+#define SM4_INT_DONE BIT(3) -+#define SM3_INT_DONE BIT(2) -+#define SHA3_INT_DONE BIT(1) -+#define RSA_INT_DONE BIT(0) ++ 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); ++ } + -+/* RSSS interrupt enable */ -+#define SM4_INT_EN BIT(3) -+#define SM3_INT_EN BIT(2) -+#define SHA3_INT_EN BIT(1) -+#define RSA_INT_EN BIT(0) ++#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; + -+/* RSSS generic control */ -+#define RSA_OPERATION (BIT(18) | BIT(19)) -+#define SRAM_AHB_MODE_CPU BIT(16) -+#define SRAM_AHB_MODE_ENGINE 0x0 -+#define SRAM_BUFF_PD (BIT(5) | BIT(4)) -+#define SM4_DISABLE BIT(3) -+#define SM3_DISABLE BIT(2) -+#define SHA3_DISABLE BIT(1) ++ 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; ++ } + -+/* RSA trigger */ -+#define RSA_TRIGGER BIT(0) ++ 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; ++ } ++ } else { ++ i2c_bus->mode = DMA_MODE; ++ } + -+/* RSA key len */ -+#define RSA_E_BITS_LEN(x) ((x) << 16) -+#define RSA_M_BITS_LEN(x) (x) ++ /* ++ * 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; + -+#define RSA_STS (BIT(0) | BIT(1)) ++ if (!i2c_bus->timeout) ++ i2c_bus->timeout = 1; ++ } + -+/* RSA SRAM */ -+#define SRAM_OFFSET_EXP 0x0 -+#define SRAM_OFFSET_MOD 0x400 -+#define SRAM_OFFSET_DATA 0x800 -+#define SRAM_BLOCK_SIZE 0x400 ++ init_completion(&i2c_bus->cmd_complete); + -+#define ASPEED_RSA_MAX_KEY_LEN 512 /* RSA maximum key length (Bytes) */ ++ i2c_bus->irq = platform_get_irq(pdev, 0); ++ if (i2c_bus->irq < 0) ++ return i2c_bus->irq; + -+#define CRYPTO_FLAGS_BUSY BIT(1) ++ platform_set_drvdata(pdev, i2c_bus); + -+/* SHA3 command */ -+#define SHA3_CMD_TRIG BIT(31) -+#define SHA3_CMD_MODE_224 (0x0 << 28) -+#define SHA3_CMD_MODE_256 (0x1 << 28) -+#define SHA3_CMD_MODE_384 (0x2 << 28) -+#define SHA3_CMD_MODE_512 (0x3 << 28) -+#define SHA3_CMD_MODE_S128 (0x4 << 28) -+#define SHA3_CMD_MODE_S256 (0x5 << 28) -+#define SHA3_CMD_HW_PAD BIT(27) -+#define SHA3_CMD_ACC_FINAL BIT(26) -+#define SHA3_CMD_ACC BIT(25) -+#define SHA3_CMD_SG_MODE BIT(24) -+#define SHA3_CMD_IN_RST BIT(21) -+#define SHA3_CMD_OUT_RST BIT(20) -+#define SHA3_CMD_OUT_LEN(x) ((x) & 0x1ffff) ++ 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"); + -+#define SHA3_FLAGS_SHA224 BIT(0) -+#define SHA3_FLAGS_SHA256 BIT(1) -+#define SHA3_FLAGS_SHA384 BIT(2) -+#define SHA3_FLAGS_SHA512 BIT(3) -+#define SHA3_FLAGS_FINUP BIT(0xa) -+#define SHA3_FLAGS_MASK (0xff) ++ i2c_bus->apb_clk = clk_get_rate(i2c_bus->clk); + -+#define SHA3_STS BIT(0) ++ i2c_parse_fw_timings(i2c_bus->dev, &i2c_bus->timing_info, true); + -+#define SG_LAST_LIST BIT(31) ++ /* 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)); + -+#define SHA_OP_INIT BIT(0) -+#define SHA_OP_UPDATE BIT(1) -+#define SHA_OP_FINAL BIT(2) ++ ast2600_i2c_init(i2c_bus); + -+#define ASPEED_HASH_SRC_DMA_BUF_LEN 0xa000 ++ 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); + -+#define ASPEED_RSSS_POLLING_TIME 100 -+#define ASPEED_RSSS_TIMEOUT 100000 /* 100 ms */ ++ /* Set interrupt generation of i2c controller */ ++ writel(AST2600_I2CM_PKT_DONE | AST2600_I2CM_BUS_RECOVER, ++ i2c_bus->reg_base + AST2600_I2CM_IER); + -+struct aspeed_rsss_dev; ++ ret = devm_i2c_add_adapter(dev, &i2c_bus->adap); ++ if (ret) ++ return ret; + -+typedef int (*aspeed_rsss_fn_t)(struct aspeed_rsss_dev *); ++ 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; ++ } + -+struct aspeed_sg_list { -+ __le64 phy_addr; -+ __le32 len; -+}; ++ 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); + -+struct aspeed_engine_rsa { -+ struct tasklet_struct done_task; -+ unsigned long flags; -+ struct akcipher_request *req; ++ return 0; ++} + -+ /* RSA input/output SRAM buffer */ -+ void __iomem *sram_exp; -+ void __iomem *sram_mod; -+ void __iomem *sram_data; ++static void ast2600_i2c_remove(struct platform_device *pdev) ++{ ++ struct ast2600_i2c_bus *i2c_bus = platform_get_drvdata(pdev); + -+ /* callback func */ -+ aspeed_rsss_fn_t resume; ++ /* Disable everything. */ ++ writel(0, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); ++ writel(0, i2c_bus->reg_base + AST2600_I2CM_IER); ++} ++ ++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); + -+struct aspeed_engine_sha3 { -+ struct tasklet_struct done_task; -+ unsigned long flags; -+ struct ahash_request *req; ++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, ++ }, ++}; + -+ /* Protects sha3 engine operation enqueue in order */ -+ struct mutex queue_lock; ++module_platform_driver(ast2600_i2c_bus_driver); + -+ /* input buffer for SG */ -+ void *ahash_src_addr; -+ dma_addr_t ahash_src_dma_addr; ++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) + -+ /* input buffer for remain */ -+ void *buffer_addr; -+ dma_addr_t buffer_dma_addr; ++#define DEV_ADDR_TABLE_LOC(start, idx) ((start) + ((idx) << 2)) + -+ /* output buffer */ -+ void *digest_addr; -+ dma_addr_t digest_dma_addr; ++#define DEVICE_CTRL 0x0 ++#define DEV_CTRL_SLAVE_MDB GENMASK(23, 16) ++#define DEV_CTRL_HOT_JOIN_NACK BIT(8) + -+ dma_addr_t src_dma; -+ size_t src_length; ++#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 + -+ /* callback func */ -+ aspeed_rsss_fn_t resume; -+ aspeed_rsss_fn_t dma_prepare; ++#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) + -+ unsigned sg_mode:1; -+}; ++#define IBI_QUEUE_STATUS 0x18 + -+struct aspeed_rsss_dev { -+ void __iomem *regs; -+ struct device *dev; -+ int irq; -+ struct clk *clk; -+ struct reset_control *reset_rsa; -+ struct reset_control *reset_sha3; ++#define IBI_SIR_REQ_REJECT 0x30 ++#define INTR_STATUS_EN 0x40 ++#define INTR_SIGNAL_EN 0x44 ++#define INTR_IBI_THLD_STAT BIT(2) + -+ struct crypto_engine *crypt_engine_rsa; -+ struct crypto_engine *crypt_engine_sha3; ++#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 aspeed_engine_rsa rsa_engine; -+ struct aspeed_engine_sha3 sha3_engine; ++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; + -+enum aspeed_algo_type { -+ ASPEED_ALGO_TYPE_AKCIPHER, -+ ASPEED_ALGO_TYPE_AHASH, -+}; ++ struct ast2600_i3c_swdat_group dat_group[NUM_OF_SWDAT_GROUP]; + }; + ++static u8 even_parity(u8 p) ++{ ++ p ^= p >> 4; ++ p &= 0xf; + -+struct aspeed_rsss_alg { -+ struct aspeed_rsss_dev *rsss_dev; -+ enum aspeed_algo_type type; -+ union { -+ struct akcipher_engine_alg akcipher; -+ struct ahash_engine_alg ahash; -+ } alg; -+}; ++ return (0x9669 >> p) & 1; ++} + -+/* RSA related */ -+struct aspeed_rsa_ctx { -+ struct aspeed_rsss_dev *rsss_dev; ++static inline struct dw_i3c_master * ++to_dw_i3c_master(struct i3c_master_controller *master) ++{ ++ return container_of(master, struct dw_i3c_master, base); ++} + -+ struct rsa_key key; -+ int enc; -+ 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; + 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); + -+ aspeed_rsss_fn_t trigger; ++ 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); + -+ struct crypto_akcipher *fallback_tfm; -+}; ++ 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); ++} + -+enum aspeed_rsa_key_mode { -+ ASPEED_RSA_EXP_MODE = 0, -+ ASPEED_RSA_MOD_MODE, -+ ASPEED_RSA_DATA_MODE, -+}; ++static void ast2600_i3c_exit_sw_mode(struct dw_i3c_master *dw) ++{ ++ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); + -+/* Hash related */ -+struct aspeed_sha3_ctx { -+ struct aspeed_rsss_dev *rsss_dev; -+}; ++ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), ++ SCL_IN_SW_MODE_EN | SDA_IN_SW_MODE_EN, 0); ++} + -+struct aspeed_sha3_reqctx { -+ unsigned long flags; /* final update flag should no use */ -+ unsigned long op; /* final or update */ -+ u32 cmd; /* trigger cmd */ ++static void ast2600_i3c_toggle_scl_in(struct dw_i3c_master *dw, int count) ++{ ++ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); + -+ /* walk state */ -+ struct scatterlist *src_sg; -+ int src_nents; -+ unsigned int offset; /* offset in current sg */ -+ unsigned int total; /* per update length */ ++ 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); ++ } ++} + -+ size_t digsize; -+ size_t blksize; ++static void ast2600_i3c_gen_internal_stop(struct dw_i3c_master *dw) ++{ ++ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); + -+ /* remain data buffer */ -+ u8 buffer[SHA3_512_BLOCK_SIZE * 2]; -+ size_t bufcnt; /* buffer counter */ ++ 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); ++} + -+ /* output buffer */ -+ u8 digest[SHA3_512_DIGEST_SIZE]; -+ u64 digcnt[2]; -+}; ++static int aspeed_i3c_bus_recovery(struct dw_i3c_master *dw) ++{ ++ 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); + -+#define ast_rsss_write(rsss, val, offset) \ -+ writel((val), (rsss)->regs + (offset)) ++ 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; ++ } ++ } + -+#define ast_rsss_read(rsss, offset) \ -+ readl((rsss)->regs + (offset)) -+ -+int aspeed_rsss_rsa_init(struct aspeed_rsss_dev *rsss_dev); -+void aspeed_rsss_rsa_exit(struct aspeed_rsss_dev *rsss_dev); -+int aspeed_rsss_sha3_init(struct aspeed_rsss_dev *rsss_dev); -+void aspeed_rsss_sha3_exit(struct aspeed_rsss_dev *rsss_dev); -+ -+extern struct aspeed_rsss_alg aspeed_rsss_algs_rsa; -+extern struct aspeed_rsss_alg aspeed_rsss_algs_sha3_224; -+extern struct aspeed_rsss_alg aspeed_rsss_algs_sha3_256; -+extern struct aspeed_rsss_alg aspeed_rsss_algs_sha3_384; -+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 2026-04-08 18:03:23.257162538 +0000 -+++ b/drivers/edac/Kconfig 2026-04-08 18:03:33.347978488 +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/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 2026-04-08 18:03:48.122708755 +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); ++ 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"); + - 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, -+}; ++ return ret; ++} + -+static const struct aspeed_fsi_match_data ast2700_match_data = { -+ .sup_ahb_access = 1, -+}; ++static void ast2600_i3c_gen_target_reset_pattern(struct dw_i3c_master *dw) ++{ ++ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); ++ int i; + - 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 2026-04-08 18:03:35.024947902 +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. ++ 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; ++ } + - 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 2026-04-08 18:03:39.921858587 +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 2026-04-08 18:03:48.238706636 +0000 -@@ -0,0 +1,469 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (c) 2024 ASPEED -+ * -+ * Author: Billy Tsai -+ */ ++ 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); ++} + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++static bool ast2600_i3c_fsm_exit_serv_ibi(struct dw_i3c_master *dw) ++{ ++ u32 state; + -+#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) ++ /* ++ * 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; + -+static inline u32 field_get(u32 _mask, u32 _val) -+{ -+ return (((_val) & (_mask)) >> (ffs(_mask) - 1)); ++ return true; +} + -+static inline u32 field_prep(u32 _mask, u32 _val) ++static void ast2600_i3c_gen_tbits_in(struct dw_i3c_master *dw) +{ -+ return (((_val) << (ffs(_mask) - 1)) & (_mask)); -+} ++ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); ++ bool is_idle; ++ int ret; + -+static inline void ast_write_bits(void __iomem *addr, u32 mask, u32 val) -+{ -+ iowrite32((ioread32(addr) & ~(mask)) | field_prep(mask, val), addr); -+} ++ 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); + -+static inline void ast_clr_bits(void __iomem *addr, u32 mask) -+{ -+ iowrite32((ioread32(addr) & ~(mask)), addr); ++ 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 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) ++static void ast2600_i3c_set_ibi_mdb(struct dw_i3c_master *dw, u8 mdb) +{ -+ bitmap_set(valid_mask, 0, ngpios); -+ return 0; ++ 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 void aspeed_ltpi_gpio_irq_init_valid_mask(struct gpio_chip *gc, -+ unsigned long *valid_mask, -+ unsigned int ngpios) ++static int ast2600_i3c_get_free_hw_pos(struct dw_i3c_master *dw) +{ -+ unsigned int i; ++ if (!(dw->free_pos & GENMASK(dw->maxdevs - 1, 0))) ++ return -ENOSPC; + -+ /* input GPIOs are even bits */ -+ for (i = 0; i < ngpios; i++) { -+ if (i % 2) -+ clear_bit(i, valid_mask); -+ } ++ return ffs(dw->free_pos) - 1; +} + -+static int aspeed_ltpi_gpio_irq_init_hw(struct gpio_chip *gc) ++static void ast2600_i3c_init_swdat(struct dw_i3c_master *dw) +{ -+ struct aspeed_ltpi_gpio *gpio = gpiochip_get_data(gc); -+ void __iomem *addr; -+ unsigned long flags; -+ int i; ++ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); ++ struct ast2600_i3c_swdat_group *gp; ++ int i, j; ++ u32 def_set, def_clr; + -+ raw_spin_lock_irqsave(&gpio->lock, flags); ++ def_clr = DEV_ADDR_TABLE_IBI_ADDR_MASK; ++ def_set = DEV_ADDR_TABLE_MR_REJECT | DEV_ADDR_TABLE_SIR_REJECT; + -+ 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); -+ } ++ 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; + -+ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ for (j = 0; j < NUM_OF_SWDATS_IN_GROUP; j++) ++ gp->dat[j] = 0; ++ } + -+ return 0; ++ for (i = 0; i < dw->maxdevs; i++) ++ writel(def_set, ++ dw->regs + DEV_ADDR_TABLE_LOC(dw->datstartaddr, i)); +} + -+static bool aspeed_ltpi_gpio_is_input(unsigned int offset) ++static int ast2600_i3c_set_swdat(struct dw_i3c_master *dw, u8 addr, u32 val) +{ -+ return !(offset % 2); -+} ++ 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); + -+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; ++ 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; + -+ raw_spin_lock_irqsave(&gpio->lock, flags); ++ if (val) { ++ gp->free_pos &= ~BIT(pos); + -+ mask = aspeed_ltpi_gpio_is_input(offset) ? LTPI_GPIO_IN_DATA : -+ LTPI_GPIO_OUT_DATA; -+ rc = !!(field_get(mask, ioread32(addr))); ++ /* ++ * 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; + -+ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ 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); + -+ return rc; ++ /* ++ * 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; +} + -+static int ltpi_gpio_set_value(struct gpio_chip *gc, unsigned int offset, -+ int val) ++static u32 ast2600_i3c_get_swdat(struct dw_i3c_master *dw, u8 addr) +{ -+ 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 ast2600_i3c *i3c = to_ast2600_i3c(dw); ++ struct ast2600_i3c_swdat_group *gp = &i3c->dat_group[ADDR_GRP(addr)]; + -+ if (aspeed_ltpi_gpio_is_input(offset)) -+ return -EINVAL; ++ return gp->dat[ADDR_HID(addr)]; ++} + -+ reg = ioread32(addr); ++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; + -+ if (val) -+ reg |= LTPI_GPIO_OUT_DATA; -+ else -+ reg &= ~LTPI_GPIO_OUT_DATA; ++ if (!dat || hw_index < 0) ++ return -1; + -+ iowrite32(reg, addr); ++ dat &= ~gp->mask.clr; ++ dat |= gp->mask.set; ++ writel(dat, dw->regs + DEV_ADDR_TABLE_LOC(dw->datstartaddr, hw_index)); + + return 0; +} + -+static void aspeed_ltpi_gpio_set(struct gpio_chip *gc, unsigned int offset, -+ int val) ++static int ast2600_i3c_get_swdat_hw_pos(struct dw_i3c_master *dw, u8 addr) +{ -+ struct aspeed_ltpi_gpio *gpio = gpiochip_get_data(gc); -+ unsigned long flags; ++ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); ++ struct ast2600_i3c_swdat_group *gp = &i3c->dat_group[ADDR_GRP(addr)]; + -+ raw_spin_lock_irqsave(&gpio->lock, flags); -+ ltpi_gpio_set_value(gc, offset, val); -+ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ return gp->hw_index; +} + -+static int aspeed_ltpi_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) ++static int ast2600_i3c_reattach_i3c_dev(struct i3c_dev_desc *dev, ++ u8 old_dyn_addr) +{ -+ return aspeed_ltpi_gpio_is_input(offset) ? 0 : -EINVAL; -+} ++ 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); + -+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; ++ if (old_dyn_addr != dev->info.dyn_addr) ++ ast2600_i3c_set_swdat(master, old_dyn_addr, 0); + -+ raw_spin_lock_irqsave(&gpio->lock, flags); -+ rc = ltpi_gpio_set_value(gc, offset, val); -+ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ 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; + -+ return rc; ++ return 0; +} + -+static int aspeed_ltpi_gpio_get_direction(struct gpio_chip *gc, -+ unsigned int offset) ++static int ast2600_i3c_attach_i3c_dev(struct i3c_dev_desc *dev) +{ -+ 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; ++ 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; + -+ *offset = irqd_to_hwirq(d); -+ internal = irq_data_get_irq_chip_data(d); -+ WARN_ON(!internal); ++ pos = ast2600_i3c_set_swdat(master, addr, ++ FIELD_PREP(DEV_ADDR_TABLE_DYNAMIC_ADDR, addr)); ++ if (pos < 0) ++ return pos; + -+ *gpio = internal; -+} ++ data = kzalloc(sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; + -+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; ++ data->index = ast2600_i3c_get_swdat_hw_pos(master, addr); ++ master->devs[addr].addr = addr; ++ i3c_dev_set_master_data(dev, data); + -+ irqd_to_aspeed_ltpi_gpio_data(d, &gpio, &offset); ++ if (master->base.bus.context == I3C_BUS_CONTEXT_JESD403) { ++ dev->info.max_write_ds = 0; ++ dev->info.max_read_ds = 0; ++ } + -+ status_addr = gpio->base + LTPI_GPIO_CTRL_REG_OFFSET(offset >> 1); ++ return 0; ++} + -+ raw_spin_lock_irqsave(&gpio->lock, flags); ++static void ast2600_i3c_detach_i3c_dev(struct i3c_dev_desc *dev) ++{ ++ 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; + -+ ast_write_bits(status_addr, LTPI_GPIO_IRQ_STS, 1); ++ ast2600_i3c_set_swdat(master, addr, 0); + -+ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ i3c_dev_set_master_data(dev, NULL); ++ master->devs[addr].addr = 0; ++ kfree(data); +} + -+static void aspeed_ltpi_gpio_irq_set_mask(struct irq_data *d, bool set) ++static int ast2600_i3c_attach_i2c_dev(struct i2c_dev_desc *dev) +{ -+ struct aspeed_ltpi_gpio *gpio; -+ unsigned long flags; -+ void __iomem *addr; -+ int offset; ++ 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; + -+ irqd_to_aspeed_ltpi_gpio_data(d, &gpio, &offset); -+ addr = gpio->base + LTPI_GPIO_CTRL_REG_OFFSET(offset >> 1); ++ 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; + -+ /* Unmasking the IRQ */ -+ if (set) -+ gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d)); ++ data = kzalloc(sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; + -+ 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); ++ 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); + -+ /* Masking the IRQ */ -+ if (!set) -+ gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(d)); ++ return 0; +} + -+static void aspeed_ltpi_gpio_irq_mask(struct irq_data *d) ++static void ast2600_i3c_detach_i2c_dev(struct i2c_dev_desc *dev) +{ -+ aspeed_ltpi_gpio_irq_set_mask(d, false); -+} ++ 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); + -+static void aspeed_ltpi_gpio_irq_unmask(struct irq_data *d) -+{ -+ aspeed_ltpi_gpio_irq_set_mask(d, true); ++ ast2600_i3c_set_swdat(master, dev->addr, 0); ++ ++ i2c_dev_set_master_data(dev, NULL); ++ master->devs[dev->addr].addr = 0; ++ kfree(data); +} + -+static int aspeed_ltpi_gpio_set_type(struct irq_data *d, unsigned int type) ++static void ast2600_i3c_set_sir_enabled(struct dw_i3c_master *dw, ++ struct i3c_dev_desc *dev, u8 idx, ++ bool enable) +{ -+ u32 type0 = 0; -+ u32 type1 = 0; -+ u32 type2 = 0; -+ irq_flow_handler_t handler; -+ struct aspeed_ltpi_gpio *gpio; ++ 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; -+ void __iomem *addr; -+ int offset; ++ u32 reg; ++ bool global; + -+ irqd_to_aspeed_ltpi_gpio_data(d, &gpio, &offset); -+ addr = gpio->base + LTPI_GPIO_CTRL_REG_OFFSET(offset >> 1); ++ spin_lock_irqsave(&dw->devs_lock, flags); ++ if (enable) { ++ gp->mask.clr |= DEV_ADDR_TABLE_SIR_REJECT | ++ DEV_ADDR_TABLE_IBI_ADDR_MASK; + -+ 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; ++ 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); + } + -+ 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); ++ 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; + -+ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++ for (i = 0; i < NUM_OF_SWDATS_IN_GROUP; i++) { ++ if (!(gp->dat[i] & DEV_ADDR_TABLE_SIR_REJECT)) { ++ ibi_enable = true; ++ break; ++ } ++ } + -+ irq_set_handler_locked(d, handler); -+ return 0; -+} ++ if (!ibi_enable) { ++ reg |= BIT(gp->hw_index); ++ global = (reg == 0xffffffff) && hj_rejected; + -+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; ++ gp->mask.set = DEV_ADDR_TABLE_SIR_REJECT; ++ } ++ } ++ writel(reg, dw->regs + IBI_SIR_REQ_REJECT); + -+ chained_irq_enter(ic, desc); ++ 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); + -+ 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 = 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); ++ } + -+ reg = ioread32(addr); ++ ast2600_i3c_flush_swdat(dw, dev->info.dyn_addr); + -+ for_each_set_bit(p, ®, 32) -+ generic_handle_domain_irq(gc->irq.domain, -+ (i * 32 + p) * 2); -+ } -+ chained_irq_exit(ic, desc); ++ spin_unlock_irqrestore(&dw->devs_lock, flags); +} + -+static void aspeed_ltpi_gpio_irq_print_chip(struct irq_data *d, -+ struct seq_file *p) ++static void ast2600_i3c_set_ibi_dev(struct dw_i3c_master *dw, ++ struct i3c_dev_desc *dev) +{ -+ struct aspeed_ltpi_gpio *gpio; -+ int offset; -+ -+ irqd_to_aspeed_ltpi_gpio_data(d, &gpio, &offset); -+ seq_printf(p, dev_name(gpio->dev)); ++ dw->devs[dev->info.dyn_addr].ibi_dev = 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) ++static void ast2600_i3c_unset_ibi_dev(struct dw_i3c_master *dw, ++ struct i3c_dev_desc *dev) +{ -+ 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; ++ dw->devs[dev->info.dyn_addr].ibi_dev = NULL; +} + -+static int aspeed_ltpi_gpio_reset_tolerance(struct gpio_chip *chip, -+ unsigned int offset, bool enable) ++static struct i3c_dev_desc *ast2600_i3c_get_ibi_dev(struct dw_i3c_master *dw, ++ u8 addr) +{ -+ struct aspeed_ltpi_gpio *gpio = gpiochip_get_data(chip); -+ unsigned long flags; -+ void __iomem *reg; ++ return dw->devs[addr].ibi_dev; ++} + -+ reg = gpio->base + LTPI_GPIO_CTRL_REG_OFFSET(offset >> 1); + 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; + -+ raw_spin_lock_irqsave(&gpio->lock, flags); ++ ast2600_i3c_init_swdat(&i3c->dw); + -+ if (enable) -+ ast_write_bits(reg, LTPI_GPIO_RST_TOLERANCE, 1); -+ else -+ ast_clr_bits(reg, LTPI_GPIO_RST_TOLERANCE); + 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 + -+ raw_spin_unlock_irqrestore(&gpio->lock, flags); ++/* 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)) + -+ return 0; -+} ++#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 + -+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); ++#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 (param == PIN_CONFIG_PERSIST_STATE) -+ return aspeed_ltpi_gpio_reset_tolerance(chip, offset, arg); ++#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 -EOPNOTSUPP; -+} ++#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 const struct of_device_id aspeed_ltpi_gpio_of_table[] = { -+ { .compatible = "aspeed,ast2700-ltpi-gpio" }, -+ {} -+}; ++#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 + -+MODULE_DEVICE_TABLE(of, aspeed_ltpi_gpio_of_table); ++#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) + -+static int __init aspeed_ltpi_gpio_probe(struct platform_device *pdev) -+{ -+ u32 nr_gpios; -+ struct aspeed_ltpi_gpio *gpio; -+ int rc; ++#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) + -+ gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); -+ if (!gpio) -+ return -ENOMEM; ++#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) + -+ gpio->base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(gpio->base)) -+ return PTR_ERR(gpio->base); ++#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) + -+ gpio->dev = &pdev->dev; ++#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) + -+ 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; -+ } ++#define ASPEED_I3C_INTR_RENEW 0xF4 + -+ raw_spin_lock_init(&gpio->lock); ++/* 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)) + -+ 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; ++#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) + -+ aspeed_ltpi_gpio_setup_irqs(gpio, pdev); ++/* 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) + -+ rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); -+ if (rc < 0) -+ return rc; ++#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 + -+ return 0; -+} ++/* 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) + -+static struct platform_driver aspeed_ltpi_gpio_driver = { -+ .driver = { -+ .name = KBUILD_MODNAME, -+ .of_match_table = aspeed_ltpi_gpio_of_table, -+ }, -+}; ++#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 + -+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 2026-04-08 18:03:48.233706727 +0000 -@@ -6,6 +6,7 @@ - */ - - #include -+#include - #include - #include - #include -@@ -18,7 +19,35 @@ - #include - #include - --#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)) ++/* 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) + -+#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 ++#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 + -+#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) -@@ -26,6 +55,8 @@ - - struct aspeed_sgpio_pdata { - const u32 pin_mask; -+ const struct aspeed_sgpio_llops *llops; -+ const u32 cfg_offset; - }; - - struct aspeed_sgpio { -@@ -35,6 +66,7 @@ - raw_spinlock_t lock; - void __iomem *base; - int irq; -+ const struct aspeed_sgpio_pdata *pdata; - }; - - struct aspeed_sgpio_bank { -@@ -42,7 +74,6 @@ - u16 rdata_reg; - u16 irq_regs; - u16 tolerance_regs; -- const char names[4][3]; - }; - - /* -@@ -58,28 +89,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" }, - }, - }; - -@@ -94,6 +121,15 @@ - 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 -@@ -101,9 +137,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 +164,30 @@ - } - } - -+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; -+ } -+} ++/* 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) + - #define GPIO_BANK(x) ((x) >> 6) - #define GPIO_OFFSET(x) ((x) & GENMASK(5, 0)) - #define GPIO_BIT(x) BIT(GPIO_OFFSET(x) >> 1) -@@ -169,17 +229,13 @@ - 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); -- unsigned long flags; - enum aspeed_sgpio_reg reg; - int rc = 0; - -- raw_spin_lock_irqsave(&gpio->lock, flags); -+ guard(raw_spinlock_irqsave)(&gpio->lock); - - 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); - - return rc; - } -@@ -187,26 +243,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; - - 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); -+ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_val, val); - - return 0; - } -@@ -214,13 +255,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); - -+ 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) -@@ -231,15 +270,14 @@ - 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); -+ guard(raw_spinlock_irqsave)(&gpio->lock); ++/* 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 + - rc = sgpio_set_value(gc, offset, val); -- raw_spin_unlock_irqrestore(&gpio->lock, flags); - - return rc; - } -@@ -249,75 +287,34 @@ - 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) - { -- 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); -- -- raw_spin_lock_irqsave(&gpio->lock, flags); -+ struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d); -+ int offset = irqd_to_hwirq(d); - -- iowrite32(bit, status_addr); -+ guard(raw_spinlock_irqsave)(&gpio->lock); - -- 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); -+ 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) -@@ -335,55 +332,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 +373,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 +391,9 @@ - - 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)); -+ seq_puts(p, dev_name(gpio->dev)); - } - - static const struct irq_chip aspeed_sgpio_irq_chip = { -@@ -437,7 +410,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 +419,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 +437,91 @@ - 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; ++#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) + -+ 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); ++/* 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 + -+ 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); -+ } -+} ++#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 + -+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); ++#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) + -+ return !!(ioread32(addr) & GPIO_BIT(offset)); -+} ++#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 + -+static int aspeed_sgpio_g4_reg_bank_get(struct aspeed_sgpio *gpio, unsigned int offset, -+ const enum aspeed_sgpio_reg reg) ++static inline unsigned int aspeed_get_avail_tx_entries(struct i3c_hci *hci) +{ -+ const struct aspeed_sgpio_bank *bank = to_bank(offset); -+ void __iomem *addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg); ++ unsigned int queue_ptr, entries; + -+ if (reg == reg_irq_status) -+ return ioread32(addr); ++ 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 -+ return -EOPNOTSUPP; ++ entries = QUEUE_PTR0_TX_R(queue_ptr) - QUEUE_PTR0_TX_W(queue_ptr); ++ ++ return entries; +} + -+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, -+}; ++static inline unsigned int aspeed_get_received_rx_entries(struct i3c_hci *hci) ++{ ++ unsigned int queue_ptr, entries; + - 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_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,21 +540,77 @@ - - 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, -+}; -+ -+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; ++ 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)); + -+ if (mask) { -+ write_val = (ioread32(addr) & ~(mask)) | field_prep(mask, val); -+ iowrite32(write_val, addr); -+ } ++ return entries; +} + -+static bool aspeed_sgpio_g7_reg_bit_get(struct aspeed_sgpio *gpio, unsigned int offset, -+ const enum aspeed_sgpio_reg reg) ++static inline unsigned int aspeed_get_i3c_revision_id(struct i3c_hci *hci) +{ -+ 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; ++ return FIELD_GET(GENMASK(23, 16), hci->vendor_product_id); +} + -+static int aspeed_sgpio_g7_reg_bank_get(struct aspeed_sgpio *gpio, unsigned int offset, -+ const enum aspeed_sgpio_reg reg) ++static inline void aspeed_i3c_ccc_handler(struct i3c_hci *hci, u8 ccc) +{ -+ void __iomem *addr; ++ u32 reg; ++ u8 dynamic_addr; + -+ if (reg == reg_irq_status) { -+ addr = gpio->base + SGPIO_G7_IRQ_STS_OFFSET(offset >> 6); -+ return ioread32(addr); -+ } else { -+ return -EOPNOTSUPP; ++ 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; + } +} + -+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, ++#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.*/ ++ ++#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; +}; + -+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, - }; - - 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, }, - {} - }; - - 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; -@@ -552,12 +625,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"); -@@ -601,7 +673,7 @@ - - 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); -+ ASPEED_SGPIO_ENABLE, gpio->base + gpio->pdata->cfg_offset); - - raw_spin_lock_init(&gpio->lock); - -@@ -629,11 +701,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 2026-04-08 18:03:48.226706855 +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)) ++struct i3c_mctp_client { ++ struct i3c_mctp *priv; ++ struct ptr_ring rx_queue; ++ wait_queue_head_t wait_queue; ++}; + -+#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) ++static struct class *i3c_mctp_class; ++static dev_t i3c_mctp_devt; ++static DEFINE_IDA(i3c_mctp_ida); + - 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 }; ++static struct kmem_cache *packet_cache; + -+/* -+ * 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) ++/** ++ * 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 + */ - - 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); -+}; ++void *i3c_mctp_packet_alloc(gfp_t flags) ++{ ++ return kmem_cache_alloc(packet_cache, flags); ++} ++EXPORT_SYMBOL_GPL(i3c_mctp_packet_alloc); + - #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) ++/** ++ * 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) +{ -+ 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; -+ } ++ kmem_cache_free(packet_cache, packet); +} ++EXPORT_SYMBOL_GPL(i3c_mctp_packet_free); + - #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; ++static void i3c_mctp_client_free(struct i3c_mctp_client *client) ++{ ++ ptr_ring_cleanup(&client->rx_queue, &i3c_mctp_packet_free); + -+ 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) ++ kfree(client); ++} ++ ++static struct i3c_mctp_client *i3c_mctp_client_alloc(struct i3c_mctp *priv) +{ -+ 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 @@ - - 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; ++ struct i3c_mctp_client *client; ++ int ret; + - 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; ++ client = kzalloc(sizeof(*client), GFP_KERNEL); ++ if (!client) ++ goto out; + - 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) ++ 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) +{ -+ const struct aspeed_gpio_bank *bank = to_bank(offset); -+ void __iomem *addr = aspeed_gpio_g4_bank_reg(gpio, bank, reg); -+ u32 temp; ++ 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 (reg == reg_val) -+ temp = gpio->dcache[GPIO_BANK(offset)]; -+ else -+ temp = ioread32(addr); ++ 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; + -+ if (val) -+ temp |= GPIO_BIT(offset); -+ else -+ temp &= ~GPIO_BIT(offset); ++ return priv->default_client; ++} + -+ if (reg == reg_val) -+ gpio->dcache[GPIO_BANK(offset)] = temp; -+ iowrite32(temp, addr); ++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 bool aspeed_g4_reg_bit_get(struct aspeed_gpio *gpio, unsigned int offset, -+ const enum aspeed_gpio_reg reg) ++static void i3c_mctp_dispatch_packet(struct i3c_mctp *priv, struct i3c_mctp_packet *packet) +{ -+ const struct aspeed_gpio_bank *bank = to_bank(offset); -+ void __iomem *addr = aspeed_gpio_g4_bank_reg(gpio, bank, reg); ++ struct i3c_mctp_client *client = i3c_mctp_find_client(priv, packet); ++ int ret; + -+ return !!(ioread32(addr) & GPIO_BIT(offset)); ++ ret = ptr_ring_produce(&client->rx_queue, packet); ++ if (ret) ++ i3c_mctp_packet_free(packet); ++ else ++ wake_up_all(&client->wait_queue); +} + -+static int aspeed_g4_reg_bank_get(struct aspeed_gpio *gpio, unsigned int offset, -+ const enum aspeed_gpio_reg reg) ++static void i3c_mctp_polling_work(struct work_struct *work) +{ -+ const struct aspeed_gpio_bank *bank = to_bank(offset); -+ void __iomem *addr = aspeed_gpio_g4_bank_reg(gpio, bank, reg); ++ 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 (reg == reg_rdata || reg == reg_irq_status) -+ return ioread32(addr); -+ else -+ return -EOPNOTSUPP; ++ 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 void aspeed_g4_privilege_ctrl(struct aspeed_gpio *gpio, unsigned int offset, int cmdsrc) ++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; ++ + /* -+ * 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. ++ * Check against packet size + PEC byte ++ * to not send more data than it was set in the probe + */ -+ /* 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))); ++ 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 void aspeed_g4_privilege_init(struct aspeed_gpio *gpio) ++static ssize_t i3c_mctp_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos) +{ -+ u32 i; ++ struct i3c_mctp *priv = file->private_data; ++ struct i3c_mctp_client *client = priv->default_client; ++ struct i3c_mctp_packet *rx_packet; + -+ /* 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); -+ } ++ 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 bool aspeed_g4_copro_request(struct aspeed_gpio *gpio, unsigned int offset) ++static int i3c_mctp_open(struct inode *inode, struct file *file) +{ -+ 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 i3c_mctp *priv = container_of(inode->i_cdev, struct i3c_mctp, cdev); + -+ /* Pause the coprocessor */ -+ copro_ops->request_access(copro_data); ++ 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); + -+ /* Change command source back to ARM */ -+ aspeed_g4_privilege_ctrl(gpio, offset, GPIO_CMDSRC_ARM); ++ file->private_data = priv; + -+ /* Update cache */ -+ gpio->dcache[GPIO_BANK(offset)] = aspeed_g4_reg_bank_get(gpio, offset, reg_rdata); ++ return 0; ++} + -+ return true; ++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 void aspeed_g4_copro_release(struct aspeed_gpio *gpio, unsigned int offset) ++static __poll_t i3c_mctp_poll(struct file *file, struct poll_table_struct *pt) +{ -+ if (!copro_ops || !gpio->cf_copro_bankmap) -+ return; -+ if (!gpio->cf_copro_bankmap[offset >> 3]) -+ return; -+ if (!copro_ops->release_access) -+ return; ++ struct i3c_mctp *priv = file->private_data; ++ __poll_t ret = 0; + -+ /* Change command source back to ColdFire */ -+ aspeed_g4_privilege_ctrl(gpio, offset, GPIO_CMDSRC_COLDFIRE); ++ poll_wait(file, &priv->default_client->wait_queue, pt); + -+ /* Restart the coprocessor */ -+ copro_ops->release_access(copro_data); ++ if (__ptr_ring_peek(&priv->default_client->rx_queue)) ++ ret |= EPOLLIN; ++ ++ return ret; +} + -+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 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 aspeed_g7_reg_bit_set(struct aspeed_gpio *gpio, unsigned int offset, -+ const enum aspeed_gpio_reg reg, bool val) ++/** ++ * 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) +{ -+ u32 mask = aspeed_gpio_g7_reg_mask(reg); -+ void __iomem *addr = gpio->base + GPIO_G7_CTRL_REG_OFFSET(offset); -+ u32 write_val; ++ struct i3c_mctp *priv = dev_get_drvdata(i3cdev_to_dev(i3c)); ++ struct i3c_mctp_client *client; + -+ if (mask) { -+ write_val = (ioread32(addr) & ~(mask)) | field_prep(mask, val); -+ iowrite32(write_val, addr); ++ 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 bool aspeed_g7_reg_bit_get(struct aspeed_gpio *gpio, unsigned int offset, -+ const enum aspeed_gpio_reg reg) ++static void i3c_mctp_ibi_handler(struct i3c_device *dev, const struct i3c_ibi_payload *payload) +{ -+ u32 mask = aspeed_gpio_g7_reg_mask(reg); -+ void __iomem *addr; ++ struct i3c_mctp *priv = dev_get_drvdata(i3cdev_to_dev(dev)); ++ struct i3c_mctp_packet *rx_packet; + -+ addr = gpio->base + GPIO_G7_CTRL_REG_OFFSET(offset); -+ if (reg == reg_val) -+ mask = GPIO_G7_CTRL_IN_DATA; ++ rx_packet = i3c_mctp_read_packet(dev); ++ if (IS_ERR(rx_packet)) ++ return; + -+ if (mask) -+ return field_get(mask, ioread32(addr)); -+ else -+ return 0; ++ i3c_mctp_dispatch_packet(priv, rx_packet); +} + -+static int aspeed_g7_reg_bank_get(struct aspeed_gpio *gpio, unsigned int offset, -+ const enum aspeed_gpio_reg reg) ++static int i3c_mctp_init(struct i3c_driver *drv) +{ -+ void __iomem *addr; ++ int ret; + -+ if (reg == reg_irq_status) { -+ addr = gpio->base + GPIO_G7_IRQ_STS_OFFSET(offset >> 5); -+ return ioread32(addr); -+ } else { -+ return -EOPNOTSUPP; ++ 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 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 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); ++} + - /* - * 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, ++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; + -+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 */ -+ {}, -+}; ++ ret = i3c_device_request_ibi(i3cdev, &ibireq); ++ if (ret) ++ return ret; ++ ret = i3c_device_enable_ibi(i3cdev); ++ if (ret) ++ i3c_device_free_ibi(i3cdev); + -+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; ++ return ret; ++} + - 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); -+ - /* 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 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/gpu/drm/aspeed/Kconfig 2026-04-08 18:03:34.489957659 +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 2026-04-08 18:03:48.158708097 +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) -+ -+/* 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 */ ++static void i3c_mctp_disable_ibi(struct i3c_device *i3cdev) ++{ ++ i3c_device_disable_ibi(i3cdev); ++ i3c_device_free_ibi(i3cdev); ++} + -+/* 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 2026-04-08 18:03:48.152708207 +0000 -@@ -23,6 +23,44 @@ - return container_of(pipe, struct aspeed_gfx, pipe); - } - -+static void aspeed_gfx_set_g4_clock(struct aspeed_gfx *priv) ++/** ++ * 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) +{ -+ /* 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); ++ /* TODO: Implement EID assignment basing on domain ID */ ++ *eid = 1; ++ return 0; +} ++EXPORT_SYMBOL_GPL(i3c_mctp_get_eid); + -+static void aspeed_gfx_set_g6_clock_source(struct aspeed_gfx *priv, int mode_width) ++/** ++ * 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) +{ -+ 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 (i3c->desc->info.hdr_cap & BIT(I3C_HDR_DDR) && ++ IS_ENABLED(CONFIG_I3C_MCTP_HDR_DDR)) { ++ struct i3c_hdr_cmd cmds; + -+ 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; ++ 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); + -+static void aspeed_gfx_set_g7_clock(struct aspeed_gfx *priv) ++/** ++ * 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) +{ -+ /* apply 800 x 600 @ 60 on ast2700 */ -+ regmap_update_bits(priv->scu, 0x288, BIT(14), BIT(14)); -+ 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); -+} ++ struct i3c_mctp_packet *rx_packet; ++ int ret; + - static int aspeed_gfx_set_pixel_fmt(struct aspeed_gfx *priv, u32 *bpp) - { - struct drm_crtc *crtc = &priv->pipe.crtc; -@@ -59,11 +97,22 @@ - 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); -+ } ++ 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); + -+ /* 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); ++ rx_packet = ptr_ring_consume(&client->rx_queue); ++ if (!rx_packet) ++ return ERR_PTR(-EAGAIN); + -+ /* 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 +123,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); ++ return rx_packet; +} ++EXPORT_SYMBOL_GPL(i3c_mctp_receive_packet); + -+static void aspeed_gfx_set_clk(struct aspeed_gfx *priv, int mode_width) ++static void i3c_mctp_i3c_event_cb(struct i3c_device *dev, enum i3c_event event) +{ -+ 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); ++ 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 CLK_G7: -+ aspeed_gfx_set_g7_clock(priv); ++ 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 void aspeed_gfx_dp_mode_set(struct aspeed_gfx *priv, int mode_width) ++static int i3c_mctp_probe(struct i3c_device *i3cdev) +{ -+ 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; ++ 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; + } - } - - static void aspeed_gfx_crtc_mode_set_nofb(struct aspeed_gfx *priv) -@@ -87,6 +171,8 @@ - if (err) - return; - -+ 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 +223,10 @@ - * per line, rounded up) - */ - writel(priv->throd_val, priv->base + CRT_THROD); ++ ret = i3c_device_control_pec(i3cdev, true); ++ if (ret) ++ dev_warn(priv->dev, "Hardware not support pec"); + -+ /* 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 +277,17 @@ - gem = drm_fb_dma_get_gem_obj(fb, 0); - if (!gem) - return; -- writel(gem->dma_addr, priv->base + CRT_ADDR); ++ priv->default_client = i3c_mctp_client_alloc(priv); ++ if (IS_ERR(priv->default_client)) ++ goto error; + -+ 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); ++ dev_set_drvdata(i3cdev_to_dev(i3cdev), priv); + - u32 reg = readl(priv->base + CRT_CTRL1); - - /* Clear pending VBLANK IRQ */ -@@ -207,6 +302,7 @@ - static void aspeed_gfx_disable_vblank(struct drm_simple_display_pipe *pipe) - { - struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe); ++ 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"); + - 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 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c 2026-04-08 18:03:48.165707969 +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), -+}; ++ 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; ++ } + -+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), - }; - - 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; ++ i3c_device_get_info(i3cdev, &info); + -+ 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; ++ 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; + - 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; ++ 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; + -+ regmap_read(priv->scu, priv->pcie_int_reg, ®); ++ return 0; + -+ 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); -+ } ++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; ++} + -+ /*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); -+ } ++static void i3c_mctp_remove(struct i3c_device *i3cdev) ++{ ++ struct i3c_mctp *priv = dev_get_drvdata(i3cdev_to_dev(i3cdev)); + -+ /*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; -+ } ++ i3c_mctp_disable_ibi(i3cdev); ++ i3c_mctp_client_free(priv->default_client); ++ priv->default_client = NULL; ++ platform_device_unregister(priv->i3c_peci); + -+ return IRQ_NONE; ++ device_destroy(i3c_mctp_class, MKDEV(MAJOR(i3c_mctp_devt), priv->id)); ++ cdev_del(&priv->cdev); ++ ida_free(&i3c_mctp_ida, priv->id); +} + - 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) ++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; ++ ++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 aspeed_gfx *priv = to_aspeed_gfx(drm); -+ u32 reg = 0; ++ struct mctp_packet *packet; ++ u8 *data; + -+ /* 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); -+ } -+ } ++ packet = kzalloc(sizeof(*packet), GFP_ATOMIC); ++ if (!packet) ++ return NULL; ++ ++ data = kzalloc(count, GFP_ATOMIC); ++ if (!data) { ++ kfree(packet); ++ return NULL; + } + -+ /* check pcie rst status */ -+ regmap_read(priv->pcie_ep, priv->pcie_link_reg, ®); ++ packet->data = data; ++ packet->count = count; + -+ /* host vga is on or not */ -+ if (reg & priv->pcie_link_bit) -+ priv->pcie_active = 0x1; -+ else -+ priv->pcie_active = 0x0; ++ return packet; ++} + -+ dev_dbg(drm->dev, "pcie_active %x\n", priv->pcie_active); ++static void i3c_target_mctp_packet_free(void *data) ++{ ++ struct mctp_packet *packet = data; + -+ return 0; ++ kfree(packet->data); ++ kfree(packet); +} + -+static int aspeed_adaptor_detect(struct drm_device *drm) ++static struct mctp_client *i3c_target_mctp_client_alloc(struct i3c_target_mctp *priv) +{ -+ 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; ++ struct mctp_client *client; + -+ u32 dp_status_offset = 0, reg = 0; ++ client = kzalloc(sizeof(*client), GFP_KERNEL); ++ if (!client) ++ goto out; + -+ 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; ++ kref_init(&client->ref); ++ client->priv = priv; ++ ptr_ring_init(&client->rx_queue, RX_RING_COUNT, GFP_KERNEL); ++out: ++ return client; ++} + -+ 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 void i3c_target_mctp_client_free(struct kref *ref) ++{ ++ struct mctp_client *client = container_of(ref, typeof(*client), ref); + -+ 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); -+ } ++ ptr_ring_cleanup(&client->rx_queue, &i3c_target_mctp_packet_free); + -+ /* 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); -+ } -+ break; -+ case CLK_G7: -+ /* check AST DP is located on PCIE0 or PCIE1 */ -+ regmap_read(priv->scu, priv->dac_reg, ®); ++ kfree(client); ++} + -+ if (reg & DP_LOCATE_PCIE1) -+ dp_status_offset = SCU_PCIE1_DP_STATUS; -+ else -+ dp_status_offset = SCU_PCIE0_DP_STATUS; ++static void i3c_target_mctp_client_get(struct mctp_client *client) ++{ ++ kref_get(&client->ref); ++} + -+ /* 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; ++static void i3c_target_mctp_client_put(struct mctp_client *client) ++{ ++ kref_put(&client->ref, &i3c_target_mctp_client_free); ++} + -+ 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); -+ } ++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; + -+ 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); -+ } ++ spin_lock(&priv->client_lock); ++ client = priv->client; ++ if (client) ++ i3c_target_mctp_client_get(client); ++ spin_unlock(&priv->client_lock); + -+ /* 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 (!client) ++ return; + -+ /* 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); -+ } -+ } ++ packet = i3c_target_mctp_packet_alloc(count); ++ if (!packet) ++ goto err; + -+ break; -+ default: -+ priv->dp_support = 0x0; -+ priv->dp = NULL; -+ priv->dpmcu = NULL; -+ break; -+ } -+ return 0; ++ 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 int aspeed_gfx_reset(struct drm_device *drm) ++static struct mctp_client *i3c_target_mctp_create_client(struct i3c_target_mctp *priv) +{ -+ struct platform_device *pdev = to_platform_device(drm->dev); -+ struct aspeed_gfx *priv = to_aspeed_gfx(drm); ++ struct mctp_client *client; ++ int ret; + -+ 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); ++ /* Currently, we support just one client. */ ++ spin_lock_irq(&priv->client_lock); ++ ret = priv->client ? -EBUSY : 0; ++ spin_unlock_irq(&priv->client_lock); + -+ 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; ++ if (ret) ++ return ERR_PTR(ret); + -+ 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; -+ } ++ client = i3c_target_mctp_client_alloc(priv); ++ if (!client) ++ return ERR_PTR(-ENOMEM); + -+ return 0; ++ init_waitqueue_head(&client->wait_queue); ++ ++ spin_lock_irq(&priv->client_lock); ++ priv->client = client; ++ spin_unlock_irq(&priv->client_lock); ++ ++ return client; +} + - 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; ++static void i3c_target_mctp_delete_client(struct mctp_client *client) ++{ ++ struct i3c_target_mctp *priv = client->priv; + -+ /* 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; ++ spin_lock_irq(&priv->client_lock); ++ priv->client = NULL; ++ spin_unlock_irq(&priv->client_lock); + -+ /* 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; -+ } -+ } ++ i3c_target_mctp_client_put(client); ++} + -+ ret = aspeed_adaptor_detect(drm); -+ if (ret) { -+ dev_err(&pdev->dev, -+ "missing or invalid adaptor controller device tree entry"); -+ return ret; -+ } ++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; + - /* 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"); ++ client = i3c_target_mctp_create_client(priv); ++ if (IS_ERR(client)) ++ return PTR_ERR(client); + -+ /* 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; -+ } -+ } ++ file->private_data = client; + - 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; ++ return 0; ++} + -+ /* 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); ++static int i3c_target_mctp_release(struct inode *inode, struct file *file) ++{ ++ struct mctp_client *client = file->private_data; + - 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 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/gpu/drm/aspeed/aspeed_gfx_out.c 2026-04-08 18:03:48.145708335 +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; ++ i3c_target_mctp_delete_client(client); + -+ 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 0; ++} + -+ return mode_count; - } - - 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 2026-04-08 18:03:33.210980986 +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. ++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; + -+ To compile this driver as a module, choose M here: the module -+ will be called aspeed-chassis. ++ rx_packet = ptr_ring_consume_irq(&client->rx_queue); ++ if (!rx_packet) ++ return -EAGAIN; + - 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 2026-04-08 18:03:37.718898767 +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 2026-04-08 18:03:47.815714364 +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 ++ if (count < rx_packet->count) { ++ count = -EINVAL; ++ goto err_free; ++ } ++ if (count > rx_packet->count) ++ count = rx_packet->count; + -+/* #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; -+}; ++ if (copy_to_user(buf, rx_packet->data, count)) ++ count = -EFAULT; ++err_free: ++ i3c_target_mctp_packet_free(rx_packet); + -+struct aspeed_chassis { -+ struct device *dev; -+ void __iomem *base; -+ int irq; -+ /* for hwmon */ -+ const struct attribute_group *groups[2]; -+}; ++ return count; ++} + -+static ssize_t -+intrusion_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t count) ++static u8 *pec_append(u8 addr_rnw, u8 *buf, u8 len) +{ -+ unsigned long val; -+ struct aspeed_chassis *chassis = dev_get_drvdata(dev); -+ union chassis_ctrl_register chassis_ctrl; ++ u8 pec_v; + -+ if (kstrtoul(buf, 10, &val) < 0 || val != 0) -+ return -EINVAL; ++ pec_v = crc8(i3c_crc8_table, &addr_rnw, 1, 0); ++ pec_v = crc8(i3c_crc8_table, buf, len, pec_v); ++ buf[len] = pec_v; + -+ 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; ++ return buf; +} + -+static ssize_t intrusion_show(struct device *dev, struct device_attribute *attr, -+ char *buf) ++static ssize_t i3c_target_mctp_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) +{ -+ 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; ++ 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); + -+ chassis_ctrl.value = readl(chassis->base); ++ 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; + -+ 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; ++ tx_data = kzalloc(count, GFP_KERNEL); ++ if (!tx_data) { ++ ret = -ENOMEM; ++ goto free_ibi; + } + -+ return sprintf(buf, "%d\n", ret); -+} ++ if (copy_from_user(tx_data, buf, count)) { ++ ret = -EFAULT; ++ goto out_packet; ++ } + -+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); ++ 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; + -+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 -+}; ++ xfers[1].data.out = tx_data; ++ xfers[1].len = count; + -+static const struct attribute_group intrusion_dev_group = { -+ .attrs = intrusion_dev_attrs, -+ .is_visible = NULL, -+}; ++ ret = i3c_device_pending_read_notify(priv->i3cdev, &xfers[1], ++ &xfers[0]); ++ if (ret) ++ goto out_packet; ++ ret = count; + -+#ifdef USE_INTERRUPTS -+static void aspeed_chassis_status_check(struct aspeed_chassis *chassis) ++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) +{ -+ union chassis_ctrl_register chassis_ctrl; ++ struct mctp_client *client = file->private_data; ++ __poll_t ret = 0; + -+ 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); -+ } ++ poll_wait(file, &client->wait_queue, pt); + -+ 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 (__ptr_ring_peek(&client->rx_queue)) ++ ret |= EPOLLIN; + -+ 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); -+ } ++ /* ++ * 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 irqreturn_t aspeed_chassis_isr(int this_irq, void *dev_id) ++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 aspeed_chassis *chassis = dev_id; ++ struct i3c_device *i3cdev = dev_get_drvdata(dev); ++ struct i3c_target_mctp *priv = i3cdev_get_drvdata(i3cdev); ++ ssize_t ret; + -+ aspeed_chassis_status_check(chassis); -+ return IRQ_HANDLED; ++ ret = sysfs_emit(buf, "%d\n", priv->mdb_append_pec); ++ ++ return ret; +} -+#endif + -+static void aspeed_chassis_int_ctrl(struct aspeed_chassis *chassis, bool ctrl) ++static ssize_t mdb_append_pec_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) +{ -+ union chassis_ctrl_register chassis_ctrl; ++ struct i3c_device *i3cdev = dev_get_drvdata(dev); ++ struct i3c_target_mctp *priv = i3cdev_get_drvdata(i3cdev); ++ bool res; ++ int ret; + -+ 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); ++ ret = kstrtobool(buf, &res); ++ if (ret) ++ return ret; ++ ++ priv->mdb_append_pec = res; ++ ++ return count; +} + -+static const struct of_device_id aspeed_chassis_of_table[] = { -+ { .compatible = "aspeed,ast2600-chassis" }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, aspeed_chassis_of_table); ++static DEVICE_ATTR_RW(mdb_append_pec); + -+static int aspeed_chassis_probe(struct platform_device *pdev) ++static int i3c_target_mctp_probe(struct i3c_device *i3cdev) +{ -+ struct device *dev = &pdev->dev; -+ struct aspeed_chassis *priv; -+ struct device *hwmon; -+ int __maybe_unused ret; ++ struct device *parent = i3cdev_to_dev(i3cdev); ++ struct i3c_target_mctp *priv; ++ struct device *dev; ++ int ret; + -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ priv = devm_kzalloc(parent, 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 = ida_alloc(&i3c_target_mctp_ida, GFP_KERNEL); ++ if (ret < 0) ++ return ret; ++ priv->id = ret; + -+ ret = devm_request_irq(dev, priv->irq, aspeed_chassis_isr, 0, -+ dev_name(dev), priv); ++ 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) { -+ dev_err(dev, "Chassis Unable to get IRQ"); ++ ida_free(&i3c_target_mctp_ida, priv->id); + 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; ++ 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; ++ } + -+ hwmon = devm_hwmon_device_register_with_groups(dev, "aspeed_chassis", -+ priv, priv->groups); ++ /* ++ * 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; + -+ return PTR_ERR_OR_ZERO(hwmon); -+} ++ 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 struct platform_driver aspeed_chassis_driver = { -+ .probe = aspeed_chassis_probe, -+ .driver = { -+ .name = KBUILD_MODNAME, -+ .of_match_table = aspeed_chassis_of_table, -+ }, -+}; ++ i3cdev_set_drvdata(i3cdev, priv); + -+module_platform_driver(aspeed_chassis_driver); ++ i3c_target_read_register(i3cdev, &i3c_target_mctp_rx_packet_setup); + -+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 2026-04-08 18:03:47.821714254 +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; ++ crc8_populate_msb(i3c_crc8_table, I3C_CRC8_POLYNOMIAL); + -+ 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)); ++ return 0; ++err: ++ cdev_del(&priv->cdev); ++ ida_free(&i3c_target_mctp_ida, priv->id); + -+ 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)); ++ return ret; +} + -+static struct pwm_device * -+aspeed_pwm_xlate(struct pwm_chip *chip, const struct of_phandle_args *args) ++static void i3c_target_mctp_remove(struct i3c_device *i3cdev) +{ -+ struct pwm_device *pwm; ++ struct i3c_target_mctp *priv = dev_get_drvdata(i3cdev_to_dev(i3cdev)); + -+ /* period in the second cell and flags in the third cell are optional */ -+ if (args->args_count < 1) -+ return ERR_PTR(-EINVAL); ++ device_destroy(i3c_target_mctp_class, i3c_target_mctp_devt); ++ cdev_del(&priv->cdev); ++ ida_free(&i3c_target_mctp_ida, priv->id); ++} + -+ pwm = pwm_request_from_chip(chip, args->args[0], NULL); -+ if (IS_ERR(pwm)) -+ return pwm; ++static const struct i3c_device_id i3c_target_mctp_ids[] = { ++ I3C_CLASS(0xcc, 0x0), ++ { }, ++}; + -+ if (args->args_count > 1) -+ pwm->args.period = args->args[1]; ++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, ++}; + -+ pwm->args.polarity = PWM_POLARITY_NORMAL; -+ if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED) -+ pwm->args.polarity = PWM_POLARITY_INVERSED; ++static int i3c_target_mctp_init(struct i3c_driver *drv) ++{ ++ int ret; + -+ if (args->args_count > 3 && args->args[3] < U8_MAX) -+ aspeed_pwm_set_wdt_reload(chip, pwm, args->args[3]); ++ ret = alloc_chrdev_region(&i3c_target_mctp_devt, 0, ++ I3C_TARGET_MCTP_MINORS, "i3c-target-mctp"); ++ if (ret) ++ return ret; + -+ return pwm; ++ 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 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; ++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/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 +@@ -72,6 +72,8 @@ + #define ASPEED_ADC_BAT_SENSING_ENABLE BIT(13) + #define ASPEED_ADC_CTRL_CHANNEL GENMASK(31, 16) + #define ASPEED_ADC_CTRL_CHANNEL_ENABLE(ch) FIELD_PREP(ASPEED_ADC_CTRL_CHANNEL, BIT(ch)) ++#define ADC_MASK(n) ((n) < 16 ? ((1U << (n)) - 1) : 0xFFFF) ++#define ASPEED_ADC_CTRL_CHANNELS_ENABLE(chs) FIELD_PREP(ASPEED_ADC_CTRL_CHANNEL, ADC_MASK(chs)) -+ chip->of_xlate = aspeed_pwm_xlate; + #define ASPEED_ADC_INIT_POLLING_TIME 500 + #define ASPEED_ADC_INIT_TIMEOUT 500000 +@@ -82,6 +84,8 @@ + */ + #define ASPEED_ADC_DEF_SAMPLING_RATE 65000 + ++static DEFINE_IDA(aspeed_adc_ida); + - 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", - }, + struct aspeed_adc_trim_locate { + const unsigned int offset; + const unsigned int field; +@@ -95,6 +99,7 @@ + bool wait_init_sequence; + bool need_prescaler; + bool bat_sense_sup; ++ bool require_extra_eoc; + u8 scaler_bit_width; + unsigned int num_channels; + const struct aspeed_adc_trim_locate *trim_locate; +@@ -107,6 +112,7 @@ + + struct aspeed_adc_data { + struct device *dev; ++ int id; + const struct aspeed_adc_model_data *model_data; + void __iomem *base; + spinlock_t clk_lock; +@@ -119,6 +125,26 @@ + int cv; + bool battery_sensing; + struct adc_gain battery_mode_gain; ++ unsigned int required_eoc_num; ++ u16 *upper_bound; ++ u16 *lower_bound; ++ bool *upper_en; ++ bool *lower_en; ++}; ++ ++static const struct iio_event_spec aspeed_adc_events[] = { + { -+ .compatible = "aspeed,ast2700-pwm-tach", ++ .type = IIO_EV_TYPE_THRESH, ++ .dir = IIO_EV_DIR_RISING, ++ .mask_separate = ++ BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE), ++ }, ++ { ++ .type = IIO_EV_TYPE_THRESH, ++ .dir = IIO_EV_DIR_FALLING, ++ .mask_separate = ++ BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE), + }, - {}, }; - 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 2026-04-08 18:03:23.246162739 +0000 -+++ b/drivers/i2c/busses/Kconfig 2026-04-08 18:03:32.670990835 +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-04-08 18:03:23.246162739 +0000 -+++ b/drivers/i2c/busses/Makefile 2026-04-08 18:03:37.112909819 +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 2026-04-08 18:03:47.772715150 +0000 -@@ -0,0 +1,2449 @@ -+// 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 -+#define AST_DEFAULT_AC_TIMING 100000 -+ -+/* 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) + #define ASPEED_CHAN(_idx, _data_reg_addr) { \ +@@ -130,6 +156,8 @@ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ ++ .event_spec = aspeed_adc_events, \ ++ .num_event_specs = ARRAY_SIZE(aspeed_adc_events), \ + } + + static const struct iio_chan_spec aspeed_adc_iio_channels[] = { +@@ -174,18 +202,11 @@ + + static int aspeed_adc_set_trim_data(struct iio_dev *indio_dev) + { +- struct device_node *syscon; + struct regmap *scu; + u32 scu_otp, trimming_val; + struct aspeed_adc_data *data = iio_priv(indio_dev); + +- syscon = of_find_node_by_name(NULL, "syscon"); +- if (syscon == NULL) { +- dev_warn(data->dev, "Couldn't find syscon node\n"); +- return -EOPNOTSUPP; +- } +- scu = syscon_node_to_regmap(syscon); +- of_node_put(syscon); ++ scu = syscon_regmap_lookup_by_phandle(data->dev->of_node, "aspeed,scu"); + if (IS_ERR(scu)) { + dev_warn(data->dev, "Failed to get syscon regmap\n"); + return -EOPNOTSUPP; +@@ -276,36 +297,68 @@ + return 0; + } + ++static int aspeed_adc_get_voltage_raw(struct aspeed_adc_data *data, struct iio_chan_spec const *chan) ++{ ++ int val; + -+/* 0x10 : I2CM Controller Interrupt Control Register */ -+#define AST2600_I2CM_IER 0x10 -+/* 0x14 : I2CM Controller Interrupt Status Register : WC */ -+#define AST2600_I2CM_ISR 0x14 ++ val = readw(data->base + chan->address); ++ dev_dbg(data->dev, ++ "%d upper_bound: %d %x, lower_bound: %d %x, delay: %d * %d ns", ++ chan->channel, data->upper_en[chan->channel], ++ data->upper_bound[chan->channel], data->lower_en[chan->channel], ++ data->lower_bound[chan->channel], data->sample_period_ns, ++ data->required_eoc_num); ++ if (data->upper_en[chan->channel]) { ++ if (val >= data->upper_bound[chan->channel]) { ++ ndelay(data->sample_period_ns * ++ data->required_eoc_num); ++ val = readw(data->base + chan->address); ++ } ++ } ++ if (data->lower_en[chan->channel]) { ++ if (val <= data->lower_bound[chan->channel]) { ++ ndelay(data->sample_period_ns * ++ data->required_eoc_num); ++ val = readw(data->base + chan->address); ++ } ++ } ++ return val; ++} + -+#define AST2600_I2CM_ISR_MASK GENMASK(31, 21) -+#define AST2600_I2CM_SW_ISR_MASK GENMASK(31, 19) + static int aspeed_adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) + { + struct aspeed_adc_data *data = iio_priv(indio_dev); +- u32 adc_engine_control_reg_val; ++ u32 engine_ctrl_tmp_val, reg_val; + + switch (mask) { + case IIO_CHAN_INFO_RAW: +- if (data->battery_sensing && chan->channel == 7) { +- adc_engine_control_reg_val = +- readl(data->base + ASPEED_REG_ENGINE_CONTROL); +- writel(adc_engine_control_reg_val | +- FIELD_PREP(ASPEED_ADC_CH7_MODE, +- ASPEED_ADC_CH7_BAT) | +- ASPEED_ADC_BAT_SENSING_ENABLE, +- data->base + ASPEED_REG_ENGINE_CONTROL); ++ if (data->model_data->bat_sense_sup && ++ chan->channel == data->model_data->num_channels - 1) { ++ engine_ctrl_tmp_val = readl(data->base + ASPEED_REG_ENGINE_CONTROL); ++ reg_val = engine_ctrl_tmp_val & ++ ~ASPEED_ADC_CTRL_CHANNELS_ENABLE(data->model_data->num_channels); ++ reg_val |= ASPEED_ADC_CTRL_CHANNEL_ENABLE(chan->channel); ++ if (data->battery_sensing) ++ reg_val |= FIELD_PREP(ASPEED_ADC_CH7_MODE, ASPEED_ADC_CH7_BAT) | ++ ASPEED_ADC_BAT_SENSING_ENABLE; ++ writel(reg_val, data->base + ASPEED_REG_ENGINE_CONTROL); + /* + * After enable battery sensing mode need to wait some time for adc stable + * Experiment result is 1ms. + */ + mdelay(1); +- *val = readw(data->base + chan->address); +- *val = (*val * data->battery_mode_gain.mult) / +- data->battery_mode_gain.div; ++ *val = aspeed_adc_get_voltage_raw(data, chan); ++ if (data->battery_sensing) ++ *val = (*val * data->battery_mode_gain.mult) / ++ data->battery_mode_gain.div; + /* Restore control register value */ +- writel(adc_engine_control_reg_val, ++ writel(engine_ctrl_tmp_val, + data->base + ASPEED_REG_ENGINE_CONTROL); +- } else +- *val = readw(data->base + chan->address); ++ } else { ++ *val = aspeed_adc_get_voltage_raw(data, chan); ++ } + return IIO_VAL_INT; + + case IIO_CHAN_INFO_OFFSET: +@@ -368,9 +421,106 @@ + return 0; + } + ++static int aspeed_adc_read_event_config(struct iio_dev *indio_dev, ++ const struct iio_chan_spec *chan, ++ enum iio_event_type type, ++ enum iio_event_direction dir) ++{ ++ struct aspeed_adc_data *data = iio_priv(indio_dev); + -+#define AST2600_I2CM_PKT_TIMEOUT BIT(18) -+#define AST2600_I2CM_PKT_ERROR BIT(17) -+#define AST2600_I2CM_PKT_DONE BIT(16) ++ switch (dir) { ++ case IIO_EV_DIR_RISING: ++ return data->upper_en[chan->channel]; ++ case IIO_EV_DIR_FALLING: ++ return data->lower_en[chan->channel]; ++ default: ++ return -EINVAL; ++ } ++} + -+#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) ++static int aspeed_adc_write_event_config(struct iio_dev *indio_dev, ++ const struct iio_chan_spec *chan, ++ enum iio_event_type type, ++ enum iio_event_direction dir, ++ int state) ++{ ++ struct aspeed_adc_data *data = iio_priv(indio_dev); + -+#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) ++ switch (dir) { ++ case IIO_EV_DIR_RISING: ++ data->upper_en[chan->channel] = state ? 1 : 0; ++ break; ++ case IIO_EV_DIR_FALLING: ++ data->lower_en[chan->channel] = state ? 1 : 0; ++ break; ++ default: ++ return -EINVAL; ++ } + -+/* 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) ++ return 0; ++} + -+#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) ++static int aspeed_adc_write_event_value(struct iio_dev *indio_dev, ++ const struct iio_chan_spec *chan, ++ enum iio_event_type type, ++ enum iio_event_direction dir, ++ enum iio_event_info info, int val, ++ int val2) ++{ ++ struct aspeed_adc_data *data = iio_priv(indio_dev); + -+#define AST2600_I2CM_TX_CMD BIT(1) -+#define AST2600_I2CM_START_CMD BIT(0) ++ if (info != IIO_EV_INFO_VALUE) ++ return -EINVAL; + -+/* 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)) ++ switch (dir) { ++ case IIO_EV_DIR_RISING: ++ if (val >= BIT(ASPEED_RESOLUTION_BITS)) ++ return -EINVAL; ++ data->upper_bound[chan->channel] = val; ++ break; ++ case IIO_EV_DIR_FALLING: ++ data->lower_bound[chan->channel] = val; ++ break; ++ default: ++ return -EINVAL; ++ } + -+/* 0x20 : I2CS Target Interrupt Control Register */ -+#define AST2600_I2CS_IER 0x20 -+/* 0x24 : I2CS Target Interrupt Status Register */ -+#define AST2600_I2CS_ISR 0x24 ++ return 0; ++} + -+#define AST2600_I2CS_ADDR_INDICATE_MASK GENMASK(31, 30) -+#define AST2600_I2CS_SLAVE_PENDING BIT(29) -+#define AST2600_I2CS_SADDR_PENDING BIT(28) ++static int aspeed_adc_read_event_value(struct iio_dev *indio_dev, ++ const struct iio_chan_spec *chan, ++ enum iio_event_type type, ++ enum iio_event_direction dir, ++ enum iio_event_info info, int *val, ++ int *val2) ++{ ++ struct aspeed_adc_data *data = iio_priv(indio_dev); + -+#define AST2600_I2CS_WAIT_TX_DMA BIT(25) -+#define AST2600_I2CS_WAIT_RX_DMA BIT(24) ++ if (info != IIO_EV_INFO_VALUE) ++ return -EINVAL; + -+#define AST2600_I2CS_ADDR3_NAK BIT(22) -+#define AST2600_I2CS_ADDR2_NAK BIT(21) -+#define AST2600_I2CS_ADDR1_NAK BIT(20) ++ switch (dir) { ++ case IIO_EV_DIR_RISING: ++ *val = data->upper_bound[chan->channel]; ++ break; ++ case IIO_EV_DIR_FALLING: ++ *val = data->lower_bound[chan->channel]; ++ break; ++ default: ++ return -EINVAL; ++ } + -+#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) ++ return IIO_VAL_INT; ++} + -+#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) + static const struct iio_info aspeed_adc_iio_info = { + .read_raw = aspeed_adc_read_raw, + .write_raw = aspeed_adc_write_raw, ++ .read_event_config = &aspeed_adc_read_event_config, ++ .write_event_config = &aspeed_adc_write_event_config, ++ .read_event_value = &aspeed_adc_read_event_value, ++ .write_event_value = &aspeed_adc_write_event_value, + .debugfs_reg_access = aspeed_adc_reg_access, + }; + +@@ -381,6 +531,13 @@ + clk_hw_unregister_fixed_factor(clk); + } + ++static void aspeed_adc_ida_remove(void *data) ++{ ++ struct aspeed_adc_data *priv_data = data; + -+/* 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) ++ ida_simple_remove(&aspeed_adc_ida, priv_data->id); ++} + -+#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) -+ -+#define AST2600_I2CS_TX_CMD BIT(2) -+ -+#define AST2600_I2CS_DMA_LEN 0x2C -+ -+/* 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)) -+ -+/* 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 -+ -+/* 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 -+ -+#define AST2600_I2CS_ADDR_CTRL 0x40 -+ -+#define AST2600_I2CS_ADDR3_MASK GENMASK(22, 16) -+#define AST2600_I2CS_ADDR2_MASK GENMASK(14, 8) -+#define AST2600_I2CS_ADDR1_MASK GENMASK(6, 0) + 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 @@ + u32 adc_engine_control_reg_val; + unsigned long scaler_flags = 0; + char clk_name[32], clk_parent_name[32]; ++ const char *model_name; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*data)); + if (!indio_dev) +@@ -488,12 +647,44 @@ + if (IS_ERR(data->base)) + return PTR_ERR(data->base); + ++ data->upper_bound = devm_kzalloc(&pdev->dev, ++ sizeof(data->upper_bound) * ++ data->model_data->num_channels, ++ GFP_KERNEL); ++ if (!data->upper_bound) ++ return -ENOMEM; ++ data->upper_en = devm_kzalloc(&pdev->dev, ++ sizeof(data->upper_en) * ++ data->model_data->num_channels, ++ GFP_KERNEL); ++ if (!data->upper_en) ++ return -ENOMEM; ++ data->lower_bound = devm_kzalloc(&pdev->dev, ++ sizeof(data->lower_bound) * ++ data->model_data->num_channels, ++ GFP_KERNEL); ++ if (!data->lower_bound) ++ return -ENOMEM; ++ data->lower_en = devm_kzalloc(&pdev->dev, ++ sizeof(data->lower_en) * ++ data->model_data->num_channels, ++ GFP_KERNEL); ++ if (!data->lower_en) ++ return -ENOMEM; ++ data->id = ida_simple_get(&aspeed_adc_ida, 0, 0, GFP_KERNEL); ++ if (data->id < 0) ++ return data->id; ++ ret = devm_add_action_or_reset(data->dev, aspeed_adc_ida_remove, data); ++ if (ret) ++ return ret; ++ model_name = kasprintf(GFP_KERNEL, "%s-%d", ++ data->model_data->model_name, data->id); + /* Register ADC clock prescaler with source specified by device tree. */ + spin_lock_init(&data->clk_lock); + snprintf(clk_parent_name, ARRAY_SIZE(clk_parent_name), "%s", + of_clk_get_parent_name(pdev->dev.of_node, 0)); + snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-fixed-div", +- data->model_data->model_name); ++ model_name); + 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 @@ + + if (data->model_data->need_prescaler) { + snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-prescaler", +- data->model_data->model_name); ++ model_name); + 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 @@ + * setting to adjust the prescaler as well. + */ + snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-scaler", +- data->model_data->model_name); ++ model_name); + 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 @@ + + aspeed_adc_compensation(indio_dev); + /* Start all channels in normal mode. */ +- adc_engine_control_reg_val = +- readl(data->base + ASPEED_REG_ENGINE_CONTROL); +- adc_engine_control_reg_val |= ASPEED_ADC_CTRL_CHANNEL; ++ adc_engine_control_reg_val = readl(data->base + ASPEED_REG_ENGINE_CONTROL); ++ /* Disable the last channel when the controller supports battery sensing */ ++ if (data->model_data->bat_sense_sup) ++ adc_engine_control_reg_val |= ++ ASPEED_ADC_CTRL_CHANNELS_ENABLE(data->model_data->num_channels - 1); ++ else ++ adc_engine_control_reg_val |= ++ ASPEED_ADC_CTRL_CHANNELS_ENABLE(data->model_data->num_channels); + writel(adc_engine_control_reg_val, + data->base + ASPEED_REG_ENGINE_CONTROL); +- +- indio_dev->name = data->model_data->model_name; ++ adc_engine_control_reg_val = ++ FIELD_GET(ASPEED_ADC_CTRL_CHANNEL, ++ readl(data->base + ASPEED_REG_ENGINE_CONTROL)); ++ data->required_eoc_num = hweight_long(adc_engine_control_reg_val); ++ if (data->model_data->require_extra_eoc && ++ (adc_engine_control_reg_val & ++ BIT(data->model_data->num_channels - 1))) ++ data->required_eoc_num += 12; ++ indio_dev->name = model_name; + indio_dev->info = &aspeed_adc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = data->battery_sensing ? +@@ -645,6 +848,16 @@ + .field = GENMASK(7, 4), + }; + ++static const struct aspeed_adc_trim_locate ast2700_adc0_trim = { ++ .offset = 0x820, ++ .field = GENMASK(3, 0), ++}; + -+#define AST2600_I2CM_DMA_LEN_STS 0x48 -+#define AST2600_I2CS_DMA_LEN_STS 0x4C ++static const struct aspeed_adc_trim_locate ast2700_adc1_trim = { ++ .offset = 0x820, ++ .field = GENMASK(7, 4), ++}; + -+#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 const struct aspeed_adc_model_data ast2400_model_data = { + .model_name = "ast2400-adc", + .vref_fixed_mv = 2500, +@@ -653,6 +866,7 @@ + .need_prescaler = true, + .scaler_bit_width = 10, + .num_channels = 16, ++ .require_extra_eoc = 0, + }; + + static const struct aspeed_adc_model_data ast2500_model_data = { +@@ -665,6 +879,7 @@ + .scaler_bit_width = 10, + .num_channels = 16, + .trim_locate = &ast2500_adc_trim, ++ .require_extra_eoc = 0, + }; + + static const struct aspeed_adc_model_data ast2600_adc0_model_data = { +@@ -676,6 +891,7 @@ + .scaler_bit_width = 16, + .num_channels = 8, + .trim_locate = &ast2600_adc0_trim, ++ .require_extra_eoc = 1, + }; + + static const struct aspeed_adc_model_data ast2600_adc1_model_data = { +@@ -687,6 +903,29 @@ + .scaler_bit_width = 16, + .num_channels = 8, + .trim_locate = &ast2600_adc1_trim, ++ .require_extra_eoc = 1, ++}; + -+/* 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) ++static const struct aspeed_adc_model_data ast2700_adc0_model_data = { ++ .model_name = "ast2700-adc0", ++ .min_sampling_rate = 10000, ++ .max_sampling_rate = 500000, ++ .wait_init_sequence = true, ++ .bat_sense_sup = true, ++ .scaler_bit_width = 16, ++ .num_channels = 8, ++ .trim_locate = &ast2700_adc0_trim, ++}; + -+/* 0x74 : Target Device Address Register */ -+#define MSIC_CONFIG_ACTIMING1 0x74 -+#define MSIC_I2C_SET_TIMEOUT(s, m) (((s) << 16) | (m)) ++static const struct aspeed_adc_model_data ast2700_adc1_model_data = { ++ .model_name = "ast2700-adc1", ++ .min_sampling_rate = 10000, ++ .max_sampling_rate = 500000, ++ .wait_init_sequence = true, ++ .bat_sense_sup = true, ++ .scaler_bit_width = 16, ++ .num_channels = 8, ++ .trim_locate = &ast2700_adc1_trim, + }; + + static const struct of_device_id aspeed_adc_matches[] = { +@@ -694,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 }, ++ { .compatible = "aspeed,ast2700-adc0", .data = &ast2700_adc0_model_data }, ++ { .compatible = "aspeed,ast2700-adc1", .data = &ast2700_adc1_model_data }, + { } + }; + 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,7 @@ + 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_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_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 +@@ -0,0 +1,178 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Aspeed AST27XX E2M Interrupt Controller ++ * Copyright (C) 2023 ASPEED Technology Inc. ++ * ++ */ + -+/* 0x78 : Misc status */ -+#define MSIC_STATUS 0x78 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+/* 0x84 : Byte data log */ -+#define BYTE_DATA_LOG 0x84 ++#define ASPEED_AST2700_E2M_IC_SHIFT 0 ++#define ASPEED_AST2700_E2M_IC_ENABLE \ ++ GENMASK(7, ASPEED_AST2700_E2M_IC_SHIFT) ++#define ASPEED_AST2700_E2M_IC_NUM_IRQS 8 ++#define ASPEED_AST2700_E2M_IC_EN_REG 0x14 ++#define ASPEED_AST2700_E2M_IC_STS_REG 0x18 + -+#define AST2700_I2CC_GET_BUFF(x) ((x) & GENMASK(7, 0)) ++struct aspeed_e2m_ic { ++ unsigned long irq_enable; ++ unsigned long irq_shift; ++ unsigned int num_irqs; ++ unsigned int reg; ++ unsigned int en_reg; ++ unsigned int sts_reg; ++ struct regmap *e2m; ++ struct irq_domain *irq_domain; ++}; + -+/* 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 void aspeed_e2m_ic_irq_handler(struct irq_desc *desc) ++{ ++ unsigned int val; ++ unsigned long bit; ++ unsigned long enabled; ++ unsigned long max; ++ unsigned long status; ++ struct aspeed_e2m_ic *e2m_ic = irq_desc_get_handler_data(desc); ++ struct irq_chip *chip = irq_desc_get_chip(desc); ++ unsigned int mask; + -+/* 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 ++ chained_irq_enter(chip, desc); + -+#define I2C_TARGET_MSG_BUF_SIZE 4096 ++ mask = e2m_ic->irq_enable; ++ regmap_read(e2m_ic->e2m, e2m_ic->en_reg, &val); ++ enabled = val & e2m_ic->irq_enable; ++ regmap_read(e2m_ic->e2m, e2m_ic->sts_reg, &val); ++ status = val & enabled; + -+#define AST2600_I2C_DMA_SIZE 4096 ++ bit = e2m_ic->irq_shift; ++ max = e2m_ic->num_irqs + bit; + -+#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) ++ for_each_set_bit_from(bit, &status, max) { ++ generic_handle_domain_irq(e2m_ic->irq_domain, bit - e2m_ic->irq_shift); + -+#define AST2600_I2C_TIMEOUT_CLK 0x1 -+#define AST2700_I2C_TIMEOUT_CLK 0x3 ++ regmap_write_bits(e2m_ic->e2m, e2m_ic->sts_reg, mask, BIT(bit)); ++ } + -+#define AST2600_I2C_TARGET_COUNT 0x3 ++ chained_irq_exit(chip, desc); ++} + -+#define HIGH_MIN_DIV 100000000 -+#define STANDARD_HIGH_MIN_400NS 400 -+#define FAST_HIGH_MIN_60NS 60 -+#define FAST_PLUS_HIGH_MIN_26NS 26 ++static void aspeed_e2m_ic_irq_mask(struct irq_data *data) ++{ ++ struct aspeed_e2m_ic *e2m_ic = irq_data_get_irq_chip_data(data); ++ unsigned int mask; + -+#define DATAHOLD_MAX_LEVEL 3 ++ mask = BIT(data->hwirq + e2m_ic->irq_shift); ++ regmap_update_bits(e2m_ic->e2m, e2m_ic->en_reg, mask, 0); ++} + -+enum xfer_mode { -+ BYTE_MODE, -+ BUFF_MODE, -+ DMA_MODE, -+}; ++static void aspeed_e2m_ic_irq_unmask(struct irq_data *data) ++{ ++ struct aspeed_e2m_ic *e2m_ic = irq_data_get_irq_chip_data(data); ++ unsigned int bit = BIT(data->hwirq + e2m_ic->irq_shift); ++ unsigned int mask; + -+enum i2c_version { -+ AST2600, -+ AST2700, -+}; ++ mask = bit; ++ regmap_update_bits(e2m_ic->e2m, e2m_ic->en_reg, mask, bit); ++} + -+struct i2c_divisor { -+ u32 baseclk_idx; -+ u32 divisor; -+ u8 baseclk_limit; -+}; ++static int aspeed_e2m_ic_irq_set_affinity(struct irq_data *data, ++ const struct cpumask *dest, ++ bool force) ++{ ++ return -EINVAL; ++} + -+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_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; -+ /* 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 ++static struct irq_chip aspeed_scu_ic_chip = { ++ .name = "aspeed-e2m-ic", ++ .irq_mask = aspeed_e2m_ic_irq_mask, ++ .irq_unmask = aspeed_e2m_ic_irq_unmask, ++ .irq_set_affinity = aspeed_e2m_ic_irq_set_affinity, +}; + -+static u32 i2c_cal_high_min_config(struct ast2600_i2c_bus *i2c_bus, u64 base_clk) ++static int aspeed_e2m_ic_map(struct irq_domain *domain, unsigned int irq, ++ irq_hw_number_t hwirq) +{ -+ 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; ++ irq_set_chip_and_handler(irq, &aspeed_scu_ic_chip, handle_level_irq); ++ irq_set_chip_data(irq, domain->host_data); + -+ /* 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); ++ return 0; +} + -+static void ast2600_i2c_ac_timing_config(struct ast2600_i2c_bus *i2c_bus) ++static const struct irq_domain_ops aspeed_e2m_ic_domain_ops = { ++ .map = aspeed_e2m_ic_map, ++}; ++ ++static int aspeed_e2m_ic_of_init_common(struct aspeed_e2m_ic *e2m_ic, ++ struct device_node *node) +{ -+ 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; ++ int irq; ++ int rc = 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; ++ if (!node->parent) { ++ rc = -ENODEV; ++ goto err; + } + -+ regmap_read(i2c_bus->global_regs, AST2600_I2CG_CLK_DIV_CTRL, &clk_div_reg); -+ -+ 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); -+ /* 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; -+ } ++ e2m_ic->e2m = syscon_node_to_regmap(node->parent); ++ if (IS_ERR(e2m_ic->e2m)) { ++ rc = PTR_ERR(e2m_ic->e2m); ++ goto err; + } + -+ 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); ++ /* Clear status and disable all interrupt */ ++ regmap_write_bits(e2m_ic->e2m, e2m_ic->sts_reg, ++ e2m_ic->irq_enable, e2m_ic->irq_enable); ++ regmap_write_bits(e2m_ic->e2m, e2m_ic->en_reg, ++ e2m_ic->irq_enable, 0); + -+ 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; ++ irq = irq_of_parse_and_map(node, 0); ++ if (!irq) { ++ rc = -EINVAL; ++ goto err; + } + -+ 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; ++ e2m_ic->irq_domain = irq_domain_add_linear(node, e2m_ic->num_irqs, ++ &aspeed_e2m_ic_domain_ops, ++ e2m_ic); ++ if (!e2m_ic->irq_domain) { ++ rc = -ENOMEM; ++ goto err; + } + -+ data = baseclk_idx; -+ data |= scl_high_min << 20 | scl_high << 16 | scl_low << 12 | sda_data_hold << 10; ++ irq_set_chained_handler_and_data(irq, aspeed_e2m_ic_irq_handler, ++ e2m_ic); + -+ 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); ++ return 0; + -+ writel(data, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); ++err: ++ kfree(e2m_ic); ++ ++ return rc; +} + -+static void ast2700_i2c_ac_timing_config(struct ast2600_i2c_bus *i2c_bus) ++static int __init aspeed_ast2700_e2m_ic_of_init(struct device_node *node, ++ struct device_node *parent) +{ -+ 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; ++ struct aspeed_e2m_ic *e2m_ic = kzalloc(sizeof(*e2m_ic), GFP_KERNEL); + -+ /* 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 (!e2m_ic) ++ return -ENOMEM; + -+ regmap_read(i2c_bus->global_regs, AST2600_I2CG_CLK_DIV_CTRL, &clk_div_reg); ++ e2m_ic->irq_enable = ASPEED_AST2700_E2M_IC_ENABLE; ++ e2m_ic->irq_shift = ASPEED_AST2700_E2M_IC_SHIFT; ++ e2m_ic->num_irqs = ASPEED_AST2700_E2M_IC_NUM_IRQS; ++ e2m_ic->en_reg = ASPEED_AST2700_E2M_IC_EN_REG; ++ e2m_ic->sts_reg = ASPEED_AST2700_E2M_IC_STS_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; -+ } ++ return aspeed_e2m_ic_of_init_common(e2m_ic, node); ++} ++ ++IRQCHIP_DECLARE(ast2700_e2m_ic, "aspeed,ast2700-e2m-ic", ++ 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 @@ ++// 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 INTC_INT_ENABLE_REG 0x00 ++#define INTC_INT_STATUS_REG 0x04 ++#define INTC_IRQS_PER_WORD 32 ++#define INTC_IRQ_BASE 192 ++ ++struct aspeed_intc_ic { ++ void __iomem *base; ++ raw_spinlock_t intc_lock; ++ struct irq_domain *irq_domain; ++}; ++ ++static void aspeed_intc0_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); ++ struct irq_data *irq_data = irq_desc_get_irq_data(desc); ++ unsigned long hwirq; ++ ++ if (!irq_data || !intc_ic) { ++ pr_err("Invalid irq_data or intc_ic\n"); ++ return; + } + -+ /* 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 (irq_data->hwirq < INTC_IRQ_BASE + 32) { ++ pr_err("Invalid hwirq: %lu\n", irq_data->hwirq); ++ return; + } ++ hwirq = irq_data->hwirq - INTC_IRQ_BASE - 32; /* 32 is SPI offset */ + -+ /* 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); ++ chained_irq_enter(chip, desc); + -+ 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); ++ generic_handle_domain_irq(intc_ic->irq_domain, hwirq); + -+ /* 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; -+ } ++ /* ++ * 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(hwirq), intc_ic->base + INTC_INT_STATUS_REG); ++ raw_spin_unlock(&intc_ic->intc_lock); + -+ /* 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; ++ chained_irq_exit(chip, desc); ++} ++ ++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; ++ ++ if (!intc_ic) { ++ pr_err("Invalid intc_ic\n"); ++ return; + } + -+ data = baseclk_idx; -+ data |= scl_high_min << 20 | scl_high << 16 | scl_low << 12 | sda_data_hold << 10; ++ chained_irq_enter(chip, desc); + -+ 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); ++ status = readl(intc_ic->base + INTC_INT_STATUS_REG); ++ ++ 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); + } -+ dev_dbg(i2c_bus->dev, "ac: 0x%x\n", data); + -+ writel(data, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING); ++ chained_irq_exit(chip, desc); +} + -+static int ast2600_i2c_recover_bus(struct ast2600_i2c_bus *i2c_bus) ++static void aspeed_intc_irq_mask(struct irq_data *data) +{ -+ u32 state = readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF); -+ u32 ctrl; ++ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); ++ unsigned int mask; ++ ++ guard(raw_spinlock)(&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); ++} ++ ++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); ++ unmask = readl(intc_ic->base + INTC_INT_ENABLE_REG) | BIT(data->hwirq); ++ writel(unmask, intc_ic->base + INTC_INT_ENABLE_REG); ++} ++ ++static struct irq_chip aspeed_intc_chip = { ++ .name = "ASPEED INTC", ++ .irq_mask = aspeed_intc_irq_mask, ++ .irq_unmask = aspeed_intc_irq_unmask, ++}; ++ ++static int aspeed_intc_ic_map_irq_domain(struct irq_domain *domain, unsigned int irq, ++ irq_hw_number_t hwirq) ++{ ++ irq_set_chip_and_handler(irq, &aspeed_intc_chip, handle_level_irq); ++ irq_set_chip_data(irq, domain->host_data); ++ ++ return 0; ++} ++ ++static const struct irq_domain_ops aspeed_intc_ic_irq_domain_ops = { ++ .map = aspeed_intc_ic_map_irq_domain, ++}; ++ ++static int __init aspeed_intc_ic_of_init(struct device_node *node, ++ struct device_node *parent) ++{ ++ struct aspeed_intc_ic *intc_ic; + int ret = 0; -+ int r; ++ int irq, irq_count, i; + -+ dev_dbg(i2c_bus->dev, "%d-bus recovery bus [%x]\n", i2c_bus->adap.nr, state); ++ 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; ++ } ++ writel(0xffffffff, intc_ic->base + INTC_INT_STATUS_REG); ++ writel(0x0, intc_ic->base + INTC_INT_ENABLE_REG); + -+ /* 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); ++ intc_ic->irq_domain = irq_domain_add_linear(node, INTC_IRQS_PER_WORD, ++ &aspeed_intc_ic_irq_domain_ops, intc_ic); ++ if (!intc_ic->irq_domain) { ++ ret = -ENOMEM; ++ goto err_iounmap; ++ } + -+ reinit_completion(&i2c_bus->cmd_complete); -+ i2c_bus->cmd_err = 0; ++ raw_spin_lock_init(&intc_ic->intc_lock); + -+ /* 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; -+ } ++ irq_count = of_irq_count(node); ++ if (irq_count == 0) { ++ pr_err("Failed to get irq count\n"); ++ ret = -EINVAL; ++ goto err_iounmap; + } + -+ /* 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; ++ for (i = 0; i < irq_count; i++) { ++ irq = irq_of_parse_and_map(node, i); ++ if (!irq) { ++ pr_err("Failed to get irq number\n"); ++ 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); ++ } + } + ++ 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); ++ } ++ iounmap(intc_ic->base); ++err_free_ic: ++ kfree(intc_ic); + return ret; +} + -+#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; ++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 +@@ -1,61 +1,76 @@ + // SPDX-License-Identifier: GPL-2.0-or-later + /* +- * Aspeed AST24XX, AST25XX, and AST26XX SCU Interrupt Controller ++ * Aspeed AST24XX, AST25XX, AST26XX, and AST27XX SCU Interrupt Controller + * Copyright 2019 IBM Corporation + * + * Eddie James + */ + + #include ++#include + #include + #include + #include + #include +-#include ++#include + #include +-#include + +-#define ASPEED_SCU_IC_REG 0x018 +-#define ASPEED_SCU_IC_SHIFT 0 +-#define ASPEED_SCU_IC_ENABLE GENMASK(15, ASPEED_SCU_IC_SHIFT) +-#define ASPEED_SCU_IC_NUM_IRQS 7 + #define ASPEED_SCU_IC_STATUS GENMASK(28, 16) + #define ASPEED_SCU_IC_STATUS_SHIFT 16 ++#define AST2700_SCU_IC_STATUS GENMASK(15, 0) + +-#define ASPEED_AST2600_SCU_IC0_REG 0x560 +-#define ASPEED_AST2600_SCU_IC0_SHIFT 0 +-#define ASPEED_AST2600_SCU_IC0_ENABLE \ +- GENMASK(5, ASPEED_AST2600_SCU_IC0_SHIFT) +-#define ASPEED_AST2600_SCU_IC0_NUM_IRQS 6 +- +-#define ASPEED_AST2600_SCU_IC1_REG 0x570 +-#define ASPEED_AST2600_SCU_IC1_SHIFT 4 +-#define ASPEED_AST2600_SCU_IC1_ENABLE \ +- GENMASK(5, ASPEED_AST2600_SCU_IC1_SHIFT) +-#define ASPEED_AST2600_SCU_IC1_NUM_IRQS 2 ++struct aspeed_scu_ic_variant { ++ const char *compatible; ++ unsigned long irq_enable; ++ unsigned long irq_shift; ++ unsigned int num_irqs; ++ bool split_ier_isr; ++ unsigned long ier; ++ unsigned long isr; ++}; + -+ /* 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; -+ } -+ } ++#define SCU_VARIANT(_compat, _shift, _enable, _num, _split, _ier, _isr) { \ ++ .compatible = _compat, \ ++ .irq_shift = _shift, \ ++ .irq_enable = _enable, \ ++ .num_irqs = _num, \ ++ .split_ier_isr = _split, \ ++ .ier = _ier, \ ++ .isr = _isr, \ ++} ++ ++static const struct aspeed_scu_ic_variant scu_ic_variants[] __initconst = { ++ SCU_VARIANT("aspeed,ast2400-scu-ic", 0, GENMASK(15, 0), 7, false, 0, 0), ++ SCU_VARIANT("aspeed,ast2500-scu-ic", 0, GENMASK(15, 0), 7, false, 0, 0), ++ SCU_VARIANT("aspeed,ast2600-scu-ic0", 0, GENMASK(5, 0), 6, false, 0, 0), ++ SCU_VARIANT("aspeed,ast2600-scu-ic1", 4, GENMASK(5, 4), 2, false, 0, 0), ++ SCU_VARIANT("aspeed,ast2700-scu-ic0", 0, GENMASK(3, 0), 4, true, 0x00, 0x04), ++ SCU_VARIANT("aspeed,ast2700-scu-ic1", 0, GENMASK(3, 0), 4, true, 0x00, 0x04), ++ SCU_VARIANT("aspeed,ast2700-scu-ic2", 0, GENMASK(3, 0), 4, true, 0x04, 0x00), ++ SCU_VARIANT("aspeed,ast2700-scu-ic3", 0, GENMASK(1, 0), 2, true, 0x04, 0x00), ++}; + + struct aspeed_scu_ic { +- unsigned long irq_enable; +- unsigned long irq_shift; +- unsigned int num_irqs; +- unsigned int reg; +- struct regmap *scu; +- struct irq_domain *irq_domain; ++ unsigned long irq_enable; ++ unsigned long irq_shift; ++ unsigned int num_irqs; ++ void __iomem *base; ++ struct irq_domain *irq_domain; ++ bool split_ier_isr; ++ unsigned long ier; ++ unsigned long isr; + }; + +-static void aspeed_scu_ic_irq_handler(struct irq_desc *desc) +-{ +- unsigned int sts; +- unsigned long bit; +- unsigned long enabled; +- unsigned long max; +- unsigned long status; ++static void aspeed_scu_ic_irq_handler_combined(struct irq_desc *desc) ++{ + struct aspeed_scu_ic *scu_ic = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); +- unsigned int mask = scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT; ++ unsigned long bit, enabled, max, status; ++ unsigned int sts, mask; + + chained_irq_enter(chip, desc); + ++ mask = scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT; + /* + * The SCU IC has just one register to control its operation and read + * status. The interrupt enable bits occupy the lower 16 bits of the +@@ -66,7 +81,7 @@ + * shifting the status down to get the mapping and then back up to + * clear the bit. + */ +- regmap_read(scu_ic->scu, scu_ic->reg, &sts); ++ sts = readl(scu_ic->base); + enabled = sts & scu_ic->irq_enable; + status = (sts >> ASPEED_SCU_IC_STATUS_SHIFT) & enabled; + +@@ -76,15 +91,41 @@ + for_each_set_bit_from(bit, &status, max) { + generic_handle_domain_irq(scu_ic->irq_domain, + bit - scu_ic->irq_shift); ++ writel((readl(scu_ic->base) & ~mask) | ++ BIT(bit + ASPEED_SCU_IC_STATUS_SHIFT), ++ scu_ic->base); + } + -+ if (!target_find) -+ dev_err(i2c_bus->dev, "address [%x] could not find\n", addr); ++ chained_irq_exit(chip, desc); +} + -+static void ast2700_i2c_target_packet_dma_irq(struct ast2600_i2c_bus *i2c_bus, u32 isr) ++static void aspeed_scu_ic_irq_handler_split(struct irq_desc *desc) +{ -+ int target_rx_len = 0; -+ u32 cmd = 0; -+ u8 value; -+ int i; -+ u32 sirq_log; -+ u32 sts; ++ struct aspeed_scu_ic *scu_ic = irq_desc_get_handler_data(desc); ++ struct irq_chip *chip = irq_desc_get_chip(desc); ++ unsigned long bit, enabled, max, status; ++ unsigned int sts, mask; + -+ 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); ++ chained_irq_enter(chip, desc); + +- regmap_write_bits(scu_ic->scu, scu_ic->reg, mask, +- BIT(bit + ASPEED_SCU_IC_STATUS_SHIFT)); ++ mask = scu_ic->irq_enable; ++ sts = readl(scu_ic->base + scu_ic->isr); ++ enabled = sts & scu_ic->irq_enable; ++ sts = readl(scu_ic->base + scu_ic->isr); ++ status = sts & enabled; + -+ 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; ++ bit = scu_ic->irq_shift; ++ max = scu_ic->num_irqs + bit; + -+ 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; -+ } ++ for_each_set_bit_from(bit, &status, max) { ++ generic_handle_domain_irq(scu_ic->irq_domain, bit - scu_ic->irq_shift); ++ writel(BIT(bit), scu_ic->base + scu_ic->isr); // clear interrupt + } + + chained_irq_exit(chip, desc); + } + +-static void aspeed_scu_ic_irq_mask(struct irq_data *data) ++static void aspeed_scu_ic_irq_mask_combined(struct irq_data *data) + { + struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data); + unsigned int mask = BIT(data->hwirq + scu_ic->irq_shift) | +@@ -95,10 +136,10 @@ + * operation from clearing the status bits, they should be under the + * mask and written with 0. + */ +- regmap_update_bits(scu_ic->scu, scu_ic->reg, mask, 0); ++ writel(readl(scu_ic->base) & ~mask, scu_ic->base); + } + +-static void aspeed_scu_ic_irq_unmask(struct irq_data *data) ++static void aspeed_scu_ic_irq_unmask_combined(struct irq_data *data) + { + struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data); + unsigned int bit = BIT(data->hwirq + scu_ic->irq_shift); +@@ -110,7 +151,23 @@ + * operation from clearing the status bits, they should be under the + * mask and written with 0. + */ +- regmap_update_bits(scu_ic->scu, scu_ic->reg, mask, bit); ++ writel((readl(scu_ic->base) & ~mask) | bit, scu_ic->base); ++} + -+ 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 ((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; -+ } ++static void aspeed_scu_ic_irq_mask_split(struct irq_data *data) ++{ ++ struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data); + -+ sts &= ~(AST2600_I2CS_PKT_DONE | AST2600_I2CS_PKT_ERROR); ++ writel(readl(scu_ic->base) & ~BIT(data->hwirq + scu_ic->irq_shift), ++ scu_ic->base + scu_ic->ier); ++} + -+ 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]); -+ } -+ } -+ 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) ++static void aspeed_scu_ic_irq_unmask_split(struct irq_data *data) +{ -+ 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); ++ struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data); ++ unsigned int bit = BIT(data->hwirq + scu_ic->irq_shift); + -+ i2c_bus->target = i2c_bus->multi_target[AST2600_I2CS_GET_TARGET(sts)]; ++ writel(readl(scu_ic->base) | bit, scu_ic->base + scu_ic->ier); + } + + static int aspeed_scu_ic_irq_set_affinity(struct irq_data *data, +@@ -120,17 +177,29 @@ + return -EINVAL; + } + +-static struct irq_chip aspeed_scu_ic_chip = { +- .name = "aspeed-scu-ic", +- .irq_mask = aspeed_scu_ic_irq_mask, +- .irq_unmask = aspeed_scu_ic_irq_unmask, +- .irq_set_affinity = aspeed_scu_ic_irq_set_affinity, ++static struct irq_chip aspeed_scu_ic_chip_combined = { ++ .name = "aspeed-scu-ic", ++ .irq_mask = aspeed_scu_ic_irq_mask_combined, ++ .irq_unmask = aspeed_scu_ic_irq_unmask_combined, ++ .irq_set_affinity = aspeed_scu_ic_irq_set_affinity, ++}; + -+ /* 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 struct irq_chip aspeed_scu_ic_chip_split = { ++ .name = "ast2700-scu-ic", ++ .irq_mask = aspeed_scu_ic_irq_mask_split, ++ .irq_unmask = aspeed_scu_ic_irq_unmask_split, ++ .irq_set_affinity = aspeed_scu_ic_irq_set_affinity, + }; + + static int aspeed_scu_ic_map(struct irq_domain *domain, unsigned int irq, + irq_hw_number_t hwirq) + { +- irq_set_chip_and_handler(irq, &aspeed_scu_ic_chip, handle_level_irq); ++ struct aspeed_scu_ic *scu_ic = domain->host_data; + -+ 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; -+ } -+ -+ sts &= ~(AST2600_I2CS_PKT_DONE | AST2600_I2CS_PKT_ERROR | AST2600_I2CS_ADDR_INDICATE_MASK); -+ -+ 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); -+ -+ 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); -+ 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); -+ -+ 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; ++ if (scu_ic->split_ier_isr) ++ irq_set_chip_and_handler(irq, &aspeed_scu_ic_chip_split, handle_level_irq); ++ else ++ irq_set_chip_and_handler(irq, &aspeed_scu_ic_chip_combined, handle_level_irq); + irq_set_chip_data(irq, domain->host_data); + + return 0; +@@ -146,18 +215,19 @@ + int irq; + int rc = 0; + +- if (!node->parent) { +- rc = -ENODEV; ++ scu_ic->base = of_iomap(node, 0); ++ if (IS_ERR(scu_ic->base)) { ++ rc = PTR_ERR(scu_ic->base); + goto err; + } + +- scu_ic->scu = syscon_node_to_regmap(node->parent); +- if (IS_ERR(scu_ic->scu)) { +- rc = PTR_ERR(scu_ic->scu); +- goto err; ++ if (scu_ic->split_ier_isr) { ++ writel(AST2700_SCU_IC_STATUS, scu_ic->base + scu_ic->isr); ++ writel(0, scu_ic->base + scu_ic->ier); ++ } else { ++ writel(ASPEED_SCU_IC_STATUS, scu_ic->base); ++ writel(0, scu_ic->base); + } +- regmap_write_bits(scu_ic->scu, scu_ic->reg, ASPEED_SCU_IC_STATUS, ASPEED_SCU_IC_STATUS); +- regmap_write_bits(scu_ic->scu, scu_ic->reg, ASPEED_SCU_IC_ENABLE, 0); + + irq = irq_of_parse_and_map(node, 0); + if (!irq) { +@@ -166,14 +236,15 @@ + } + + scu_ic->irq_domain = irq_domain_add_linear(node, scu_ic->num_irqs, +- &aspeed_scu_ic_domain_ops, +- scu_ic); ++ &aspeed_scu_ic_domain_ops, scu_ic); + if (!scu_ic->irq_domain) { + rc = -ENOMEM; + goto err; + } + +- irq_set_chained_handler_and_data(irq, aspeed_scu_ic_irq_handler, ++ irq_set_chained_handler_and_data(irq, scu_ic->split_ier_isr ? ++ aspeed_scu_ic_irq_handler_split : ++ aspeed_scu_ic_irq_handler_combined, + scu_ic); + + return 0; +@@ -184,57 +255,45 @@ + return rc; + } + +-static int __init aspeed_scu_ic_of_init(struct device_node *node, +- struct device_node *parent) ++static const struct aspeed_scu_ic_variant * ++aspeed_scu_ic_find_variant(struct device_node *np) + { +- struct aspeed_scu_ic *scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL); +- +- if (!scu_ic) +- return -ENOMEM; +- +- scu_ic->irq_enable = ASPEED_SCU_IC_ENABLE; +- scu_ic->irq_shift = ASPEED_SCU_IC_SHIFT; +- scu_ic->num_irqs = ASPEED_SCU_IC_NUM_IRQS; +- scu_ic->reg = ASPEED_SCU_IC_REG; ++ for (int i = 0; i < ARRAY_SIZE(scu_ic_variants); i++) { ++ if (of_device_is_compatible(np, scu_ic_variants[i].compatible)) ++ return &scu_ic_variants[i]; + } + +- return aspeed_scu_ic_of_init_common(scu_ic, node); ++ return NULL; + } + +-static int __init aspeed_ast2600_scu_ic0_of_init(struct device_node *node, +- struct device_node *parent) ++static int __init aspeed_scu_ic_of_init(struct device_node *node, struct device_node *parent) + { +- struct aspeed_scu_ic *scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL); +- +- if (!scu_ic) +- return -ENOMEM; +- +- scu_ic->irq_enable = ASPEED_AST2600_SCU_IC0_ENABLE; +- scu_ic->irq_shift = ASPEED_AST2600_SCU_IC0_SHIFT; +- scu_ic->num_irqs = ASPEED_AST2600_SCU_IC0_NUM_IRQS; +- scu_ic->reg = ASPEED_AST2600_SCU_IC0_REG; +- +- return aspeed_scu_ic_of_init_common(scu_ic, node); +-} ++ const struct aspeed_scu_ic_variant *variant; ++ struct aspeed_scu_ic *scu_ic; + +-static int __init aspeed_ast2600_scu_ic1_of_init(struct device_node *node, +- struct device_node *parent) +-{ +- struct aspeed_scu_ic *scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL); ++ variant = aspeed_scu_ic_find_variant(node); ++ if (!variant) ++ return -ENODEV; + ++ scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL); + if (!scu_ic) + return -ENOMEM; + +- scu_ic->irq_enable = ASPEED_AST2600_SCU_IC1_ENABLE; +- scu_ic->irq_shift = ASPEED_AST2600_SCU_IC1_SHIFT; +- scu_ic->num_irqs = ASPEED_AST2600_SCU_IC1_NUM_IRQS; +- scu_ic->reg = ASPEED_AST2600_SCU_IC1_REG; ++ scu_ic->irq_enable = variant->irq_enable; ++ scu_ic->irq_shift = variant->irq_shift; ++ scu_ic->num_irqs = variant->num_irqs; ++ scu_ic->split_ier_isr = variant->split_ier_isr; ++ scu_ic->ier = variant->ier; ++ scu_ic->isr = variant->isr; + + return aspeed_scu_ic_of_init_common(scu_ic, node); + } + + IRQCHIP_DECLARE(ast2400_scu_ic, "aspeed,ast2400-scu-ic", aspeed_scu_ic_of_init); + IRQCHIP_DECLARE(ast2500_scu_ic, "aspeed,ast2500-scu-ic", aspeed_scu_ic_of_init); +-IRQCHIP_DECLARE(ast2600_scu_ic0, "aspeed,ast2600-scu-ic0", +- aspeed_ast2600_scu_ic0_of_init); +-IRQCHIP_DECLARE(ast2600_scu_ic1, "aspeed,ast2600-scu-ic1", +- aspeed_ast2600_scu_ic1_of_init); ++IRQCHIP_DECLARE(ast2600_scu_ic0, "aspeed,ast2600-scu-ic0", aspeed_scu_ic_of_init); ++IRQCHIP_DECLARE(ast2600_scu_ic1, "aspeed,ast2600-scu-ic1", aspeed_scu_ic_of_init); ++IRQCHIP_DECLARE(ast2700_scu_ic0, "aspeed,ast2700-scu-ic0", aspeed_scu_ic_of_init); ++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 (cmd) -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); ++ If you want this support, you should say Y here. + -+ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_ISR); -+ readl(i2c_bus->reg_base + AST2600_I2CS_ISR); -+} ++ To compile this driver as a module, choose M here: the module will ++ be called jtag. + -+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; ++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. + -+ /* 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 you want this support, you should say Y here. + -+ i2c_bus->target = i2c_bus->multi_target[AST2600_I2CS_GET_TARGET(sts)]; ++ 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/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 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2018 Mellanox Technologies. All rights reserved. ++// Copyright (c) 2018 Oleksandr Shamray ++// Copyright (c) 2019 Intel Corporation + -+ /* 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; ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ 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; -+ } ++#define ASPEED_JTAG_DATA 0x00 ++#define ASPEED_JTAG_INST 0x04 ++#define ASPEED_JTAG_CTRL 0x08 ++#define ASPEED_JTAG_ISR 0x0C ++#define ASPEED_JTAG_SW 0x10 ++#define ASPEED_JTAG_TCK 0x14 ++#define ASPEED_JTAG_EC 0x18 + -+ sts &= ~(AST2600_I2CS_PKT_DONE | AST2600_I2CS_PKT_ERROR | AST2600_I2CS_ADDR_INDICATE_MASK); ++#define ASPEED_JTAG_DATA_MSB 0x01 ++#define ASPEED_JTAG_DATA_CHUNK_SIZE 0x20 ++#define ASPEED_JTAG_HW2_DATA_CHUNK_SIZE 512 + -+ if (sts & AST2600_I2CS_SLAVE_MATCH) -+ i2c_bus->target_operate = 1; ++/* ASPEED_JTAG_CTRL: Engine Control 24xx and 25xx series*/ ++#define ASPEED_JTAG_CTL_ENG_EN BIT(31) ++#define ASPEED_JTAG_CTL_ENG_OUT_EN BIT(30) ++#define ASPEED_JTAG_CTL_FORCE_TMS BIT(29) ++#define ASPEED_JTAG_CTL_IR_UPDATE BIT(26) ++#define ASPEED_JTAG_CTL_INST_LEN(x) ((x) << 20) ++#define ASPEED_JTAG_CTL_LASPEED_INST BIT(17) ++#define ASPEED_JTAG_CTL_INST_EN BIT(16) ++#define ASPEED_JTAG_CTL_DR_UPDATE BIT(10) ++#define ASPEED_JTAG_CTL_DATA_LEN(x) ((x) << 4) ++#define ASPEED_JTAG_CTL_LASPEED_DATA BIT(1) ++#define ASPEED_JTAG_CTL_DATA_EN BIT(0) + -+ 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; ++/* ASPEED_JTAG_CTRL: Engine Control 26xx series*/ ++#define ASPEED_JTAG_CTL_26XX_RESET_FIFO BIT(21) ++#define ASPEED_JTAG_CTL_26XX_FIFO_MODE_CTRL BIT(20) ++#define ASPEED_JTAG_CTL_26XX_TRANS_LEN(x) ((x) << 8) ++#define ASPEED_JTAG_CTL_26XX_TRANS_MASK GENMASK(17, 8) ++#define ASPEED_JTAG_CTL_26XX_MSB_FIRST BIT(6) ++#define ASPEED_JTAG_CTL_26XX_TERM_TRANS BIT(5) ++#define ASPEED_JTAG_CTL_26XX_LASPEED_TRANS BIT(4) ++#define ASPEED_JTAG_CTL_26XX_INST_EN BIT(1) + -+ 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); ++/* ASPEED_JTAG_ISR : Interrupt status and enable */ ++#define ASPEED_JTAG_ISR_INST_PAUSE BIT(19) ++#define ASPEED_JTAG_ISR_INST_COMPLETE BIT(18) ++#define ASPEED_JTAG_ISR_DATA_PAUSE BIT(17) ++#define ASPEED_JTAG_ISR_DATA_COMPLETE BIT(16) ++#define ASPEED_JTAG_ISR_INST_PAUSE_EN BIT(3) ++#define ASPEED_JTAG_ISR_INST_COMPLETE_EN BIT(2) ++#define ASPEED_JTAG_ISR_DATA_PAUSE_EN BIT(1) ++#define ASPEED_JTAG_ISR_DATA_COMPLETE_EN BIT(0) ++#define ASPEED_JTAG_ISR_INT_EN_MASK GENMASK(3, 0) ++#define ASPEED_JTAG_ISR_INT_MASK GENMASK(19, 16) + -+ 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; -+ } ++/* ASPEED_JTAG_SW : Software Mode and Status */ ++#define ASPEED_JTAG_SW_MODE_EN BIT(19) ++#define ASPEED_JTAG_SW_MODE_TCK BIT(18) ++#define ASPEED_JTAG_SW_MODE_TMS BIT(17) ++#define ASPEED_JTAG_SW_MODE_TDIO BIT(16) + -+ 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); ++/* ASPEED_JTAG_TCK : TCK Control */ ++#define ASPEED_JTAG_TCK_DIVISOR_MASK GENMASK(11, 0) ++#define ASPEED_JTAG_TCK_GET_DIV(x) ((x) & ASPEED_JTAG_TCK_DIVISOR_MASK) + -+ 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); -+} ++/* ASPEED_JTAG_EC : Controller set for go to IDLE */ ++#define ASPEED_JTAG_EC_TRSTn_HIGH BIT(31) ++#define ASPEED_JTAG_EC_GO_IDLE BIT(0) + -+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 ASPEED_JTAG_IOUT_LEN(len) \ ++ (ASPEED_JTAG_CTL_ENG_EN | \ ++ ASPEED_JTAG_CTL_ENG_OUT_EN | \ ++ ASPEED_JTAG_CTL_INST_LEN(len)) + -+ i2c_bus->target = i2c_bus->multi_target[AST2600_I2CS_GET_TARGET(sts)]; ++#define ASPEED_JTAG_DOUT_LEN(len) \ ++ (ASPEED_JTAG_CTL_ENG_EN | \ ++ ASPEED_JTAG_CTL_ENG_OUT_EN | \ ++ ASPEED_JTAG_CTL_DATA_LEN(len)) + -+ /* 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; ++#define ASPEED_JTAG_TRANS_LEN(len) \ ++ (ASPEED_JTAG_CTL_ENG_EN | \ ++ ASPEED_JTAG_CTL_ENG_OUT_EN | \ ++ ASPEED_JTAG_CTL_26XX_TRANS_LEN(len)) + -+ 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; -+ } ++#define ASPEED_JTAG_SW_TDIO (ASPEED_JTAG_SW_MODE_EN | ASPEED_JTAG_SW_MODE_TDIO) + -+ sts &= ~(AST2600_I2CS_ADDR_INDICATE_MASK); ++#define ASPEED_JTAG_GET_TDI(direction, byte) \ ++ (((direction) & JTAG_WRITE_XFER) ? byte : UINT_MAX) + -+ 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); -+} ++#define ASPEED_JTAG_TCK_WAIT 10 ++#define ASPEED_JTAG_RESET_CNTR 10 ++#define WAIT_ITERATIONS 300 + -+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); ++/* Use this macro to switch between HW mode 1(comment out) and 2(defined) */ ++#define ASPEED_JTAG_HW_MODE_2_ENABLE 1 + -+ if (!(isr & ier)) -+ return 0; ++/* ASPEED JTAG HW MODE 2 (Only supported in AST26xx series) */ ++#define ASPEED_JTAG_SHDATA 0x20 ++#define ASPEED_JTAG_SHINST 0x24 ++#define ASPEED_JTAG_PADCTRL0 0x28 ++#define ASPEED_JTAG_PADCTRL1 0x2C ++#define ASPEED_JTAG_SHCTRL 0x30 ++#define ASPEED_JTAG_GBLCTRL 0x34 ++#define ASPEED_JTAG_INTCTRL 0x38 ++#define ASPEED_JTAG_STAT 0x3C + -+ /* -+ * 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; ++/* ASPEED_JTAG_PADCTRLx : Padding control 0 and 1 */ ++#define ASPEED_JTAG_PADCTRL_PAD_DATA BIT(24) ++#define ASPEED_JTAG_PADCTRL_POSTPAD(x) (((x) & GENMASK(8, 0)) << 12) ++#define ASPEED_JTAG_PADCTRL_PREPAD(x) (((x) & GENMASK(8, 0)) << 0) + -+ isr &= ~(AST2600_I2CS_ADDR_MASK); ++/* ASPEED_JTAG_SHCTRL: Shift Control */ ++#define ASPEED_JTAG_SHCTRL_FRUN_TCK_EN BIT(31) ++#define ASPEED_JTAG_SHCTRL_STSHIFT_EN BIT(30) ++#define ASPEED_JTAG_SHCTRL_TMS(x) (((x) & GENMASK(13, 0)) << 16) ++#define ASPEED_JTAG_SHCTRL_POST_TMS(x) (((x) & GENMASK(2, 0)) << 13) ++#define ASPEED_JTAG_SHCTRL_PRE_TMS(x) (((x) & GENMASK(2, 0)) << 10) ++#define ASPEED_JTAG_SHCTRL_PAD_SEL0 (0) ++#define ASPEED_JTAG_SHCTRL_PAD_SEL1 BIT(9) ++#define ASPEED_JTAG_SHCTRL_END_SHIFT BIT(8) ++#define ASPEED_JTAG_SHCTRL_START_SHIFT BIT(7) ++#define ASPEED_JTAG_SHCTRL_LWRDT_SHIFT(x) ((x) & GENMASK(6, 0)) + -+ 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); -+ } ++#define ASPEED_JTAG_END_SHIFT_DISABLED 0 + -+ return 1; -+} -+#endif ++/* ASPEED_JTAG_GBLCTRL : Global Control */ ++#define ASPEED_JTAG_GBLCTRL_ENG_MODE_EN BIT(31) ++#define ASPEED_JTAG_GBLCTRL_ENG_OUT_EN BIT(30) ++#define ASPEED_JTAG_GBLCTRL_FORCE_TMS BIT(29) ++#define ASPEED_JTAG_GBLCTRL_SHIFT_COMPLETE BIT(28) ++#define ASPEED_JTAG_GBLCTRL_RESET_FIFO BIT(25) ++#define ASPEED_JTAG_GBLCTRL_FIFO_CTRL_MODE BIT(24) ++#define ASPEED_JTAG_GBLCTRL_UPDT_SHIFT(x) (((x) & GENMASK(9, 7)) << 13) ++#define ASPEED_JTAG_GBLCTRL_STSHIFT(x) (((x) & GENMASK(0, 0)) << 16) ++#define ASPEED_JTAG_GBLCTRL_TRST BIT(15) ++#define ASPEED_JTAG_CLK_DIVISOR_MASK GENMASK(11, 0) ++#define ASPEED_JTAG_CLK_GET_DIV(x) ((x) & ASPEED_JTAG_CLK_DIVISOR_MASK) + -+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; ++/* ASPEED_JTAG_INTCTRL: Interrupt Control */ ++#define ASPEED_JTAG_INTCTRL_SHCPL_IRQ_EN BIT(16) ++#define ASPEED_JTAG_INTCTRL_SHCPL_IRQ_STAT BIT(0) + -+ cmd |= AST2600_I2CM_PKT_EN; ++/* ASPEED_JTAG_STAT: JTAG HW mode 2 status */ ++#define ASPEED_JTAG_STAT_ENG_IDLE BIT(0) + -+ 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; ++#define ASPEED_JTAG_MAX_PAD_SIZE 512 + -+ if (cmd & AST2600_I2CM_START_CMD) -+ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); ++/* Use this macro to set us delay to WA the intensive R/W FIFO usage issue */ ++#define AST26XX_FIFO_UDELAY 2 + -+ 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); -+ } ++/* Use this macro to set us delay for JTAG Master Controller to be programmed */ ++#define AST26XX_JTAG_CTRL_UDELAY 2 + -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); ++#define DEBUG_JTAG + -+ return 0; -+} ++static const char * const regnames[] = { ++ [ASPEED_JTAG_DATA] = "ASPEED_JTAG_DATA", ++ [ASPEED_JTAG_INST] = "ASPEED_JTAG_INST", ++ [ASPEED_JTAG_CTRL] = "ASPEED_JTAG_CTRL", ++ [ASPEED_JTAG_ISR] = "ASPEED_JTAG_ISR", ++ [ASPEED_JTAG_SW] = "ASPEED_JTAG_SW", ++ [ASPEED_JTAG_TCK] = "ASPEED_JTAG_TCK", ++ [ASPEED_JTAG_EC] = "ASPEED_JTAG_EC", ++ [ASPEED_JTAG_SHDATA] = "ASPEED_JTAG_SHDATA", ++ [ASPEED_JTAG_SHINST] = "ASPEED_JTAG_SHINST", ++ [ASPEED_JTAG_PADCTRL0] = "ASPEED_JTAG_PADCTRL0", ++ [ASPEED_JTAG_PADCTRL1] = "ASPEED_JTAG_PADCTRL1", ++ [ASPEED_JTAG_SHCTRL] = "ASPEED_JTAG_SHCTRL", ++ [ASPEED_JTAG_GBLCTRL] = "ASPEED_JTAG_GBLCTRL", ++ [ASPEED_JTAG_INTCTRL] = "ASPEED_JTAG_INTCTRL", ++ [ASPEED_JTAG_STAT] = "ASPEED_JTAG_STAT", ++}; + -+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; ++#define ASPEED_JTAG_NAME "jtag-aspeed" + -+ cmd |= AST2600_I2CM_PKT_EN; ++struct aspeed_jtag { ++ void __iomem *reg_base; ++ struct device *dev; ++ struct clk *pclk; ++ enum jtag_tapstate status; ++ int irq; ++ struct reset_control *rst; ++ u32 flag; ++ wait_queue_head_t jtag_wq; ++ u32 mode; ++ enum jtag_tapstate current_state; ++ u32 tck_period; ++ const struct jtag_low_level_functions *llops; ++ u32 pad_data_one[ASPEED_JTAG_MAX_PAD_SIZE / 32]; ++ u32 pad_data_zero[ASPEED_JTAG_MAX_PAD_SIZE / 32]; ++}; + -+ 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; ++/* ++ * Multi generation support is enabled by fops and low level assped function ++ * mapping using asped_jtag_functions struct as config mechanism. ++ */ + -+ if (cmd & AST2600_I2CM_START_CMD) -+ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); ++struct jtag_low_level_functions { ++ void (*output_disable)(struct aspeed_jtag *aspeed_jtag); ++ void (*master_enable)(struct aspeed_jtag *aspeed_jtag); ++ int (*xfer_push_data)(struct aspeed_jtag *aspeed_jtag, ++ enum jtag_xfer_type type, u32 bits_len); ++ int (*xfer_push_data_last)(struct aspeed_jtag *aspeed_jtag, ++ enum jtag_xfer_type type, u32 bits_len); ++ void (*xfer_sw)(struct aspeed_jtag *aspeed_jtag, struct jtag_xfer *xfer, ++ u32 *data); ++ int (*xfer_hw)(struct aspeed_jtag *aspeed_jtag, struct jtag_xfer *xfer, ++ u32 *data); ++ int (*trst_set)(struct aspeed_jtag *aspeed_jtag, u32 active); ++ void (*xfer_hw_fifo_delay)(void); ++ void (*xfer_sw_delay)(struct aspeed_jtag *aspeed_jtag); ++ irqreturn_t (*jtag_interrupt)(s32 this_irq, void *dev_id); ++}; + -+ 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 -EBUSY; -+ for (i = 0; i < xfer_len; i += 4) { -+ int xfer_cnt = i2c_bus->controller_xfer_cnt + i; ++struct aspeed_jtag_functions { ++ const struct jtag_ops *aspeed_jtag_ops; ++ const struct jtag_low_level_functions *aspeed_jtag_llops; ++}; + -+ 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); -+ } ++#ifdef DEBUG_JTAG ++static char *end_status_str[] = { "tlr", "idle", "selDR", "capDR", "sDR", ++ "ex1DR", "pDR", "ex2DR", "updDR", "selIR", ++ "capIR", "sIR", "ex1IR", "pIR", "ex2IR", ++ "updIR", "current" }; ++#endif + -+ if (readl(i2c_bus->reg_base + AST2600_I2CS_ISR)) -+ return -EBUSY; ++static u32 aspeed_jtag_read(struct aspeed_jtag *aspeed_jtag, u32 reg) ++{ ++ u32 val = readl(aspeed_jtag->reg_base + reg); + -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); ++#ifdef DEBUG_JTAG ++ dev_dbg(aspeed_jtag->dev, "read:%s val = 0x%08x\n", regnames[reg], val); ++#endif ++ return val; ++} + -+ return 0; ++static void aspeed_jtag_write(struct aspeed_jtag *aspeed_jtag, u32 val, u32 reg) ++{ ++#ifdef DEBUG_JTAG ++ dev_dbg(aspeed_jtag->dev, "write:%s val = 0x%08x\n", regnames[reg], ++ val); ++#endif ++ writel(val, aspeed_jtag->reg_base + reg); +} + -+static int ast2600_i2c_setup_byte_tx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) ++static int aspeed_jtag_freq_set(struct jtag *jtag, u32 freq) +{ -+ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; -+ int xfer_len; ++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); ++ unsigned long apb_frq; ++ u32 tck_val; ++ u16 div; + -+ xfer_len = msg->len - i2c_bus->controller_xfer_cnt; ++ if (!freq) ++ return -EINVAL; + -+ cmd |= AST2600_I2CM_PKT_EN; ++ apb_frq = clk_get_rate(aspeed_jtag->pclk); ++ if (!apb_frq) ++ return -EOPNOTSUPP; + -+ if (cmd & AST2600_I2CM_START_CMD) -+ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); ++ div = (apb_frq - 1) / freq; ++ if (div > ASPEED_JTAG_TCK_DIVISOR_MASK) ++ div = ASPEED_JTAG_TCK_DIVISOR_MASK; ++ tck_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_TCK); ++ aspeed_jtag_write(aspeed_jtag, ++ (tck_val & ~ASPEED_JTAG_TCK_DIVISOR_MASK) | div, ++ ASPEED_JTAG_TCK); ++ aspeed_jtag->tck_period = ++ DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC * (div + 1), apb_frq); ++ return 0; ++} + -+ if ((i2c_bus->msgs_index + 1 == i2c_bus->msgs_count) && -+ xfer_len == 1) -+ cmd |= AST2600_I2CM_STOP_CMD; ++static int aspeed_jtag_freq_set_26xx(struct jtag *jtag, u32 freq) ++{ ++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); ++ unsigned long apb_frq; ++ u32 tck_val; ++ u16 div; + -+ 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); -+ } ++ if (!freq) ++ return -EINVAL; + -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); ++ apb_frq = clk_get_rate(aspeed_jtag->pclk); ++ if (!apb_frq) ++ return -EOPNOTSUPP; + ++ div = (apb_frq - 1) / freq; ++ tck_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_GBLCTRL); ++ aspeed_jtag_write(aspeed_jtag, ++ (tck_val & ~ASPEED_JTAG_CLK_DIVISOR_MASK) | div, ++ ASPEED_JTAG_GBLCTRL); ++ aspeed_jtag->tck_period = ++ DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC * (div + 1), apb_frq); + return 0; +} + -+static int ast2600_i2c_setup_dma_rx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) ++static int aspeed_jtag_freq_get(struct jtag *jtag, u32 *frq) +{ -+ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; -+ int xfer_len = msg->len - i2c_bus->controller_xfer_cnt; -+ -+ cmd |= AST2600_I2CM_PKT_EN | AST2600_I2CM_RX_DMA_EN | AST2600_I2CM_RX_CMD; ++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); ++ u32 pclk; ++ u32 tck; + -+ 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; -+ } ++ pclk = clk_get_rate(aspeed_jtag->pclk); ++ tck = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_TCK); ++ *frq = pclk / (ASPEED_JTAG_TCK_GET_DIV(tck) + 1); + -+ writel(AST2600_I2CM_SET_RX_DMA_LEN(xfer_len - 1), i2c_bus->reg_base + AST2600_I2CM_DMA_LEN); ++ return 0; ++} + -+ if (cmd & AST2600_I2CM_START_CMD) -+ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); ++static int aspeed_jtag_freq_get_26xx(struct jtag *jtag, u32 *frq) ++{ ++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); ++ u32 pclk; ++ u32 tck; + -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); ++ pclk = clk_get_rate(aspeed_jtag->pclk); ++ tck = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_GBLCTRL); ++ *frq = pclk / (ASPEED_JTAG_CLK_GET_DIV(tck) + 1); + + return 0; +} + -+static int ast2600_i2c_setup_buff_rx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) ++static inline void aspeed_jtag_output_disable(struct aspeed_jtag *aspeed_jtag) +{ -+ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; -+ int xfer_len = msg->len - i2c_bus->controller_xfer_cnt; ++ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_CTRL); ++} + -+ cmd |= AST2600_I2CM_PKT_EN | AST2600_I2CM_RX_BUFF_EN | AST2600_I2CM_RX_CMD; ++static inline void ++aspeed_jtag_output_disable_26xx(struct aspeed_jtag *aspeed_jtag) ++{ ++ u32 reg_val; + -+ if (cmd & AST2600_I2CM_START_CMD) -+ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); ++ reg_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_GBLCTRL) & ++ ASPEED_JTAG_CLK_DIVISOR_MASK; ++ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_CTRL); ++ aspeed_jtag_write(aspeed_jtag, reg_val, ASPEED_JTAG_GBLCTRL); ++} + -+ 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; ++static inline void aspeed_jtag_master(struct aspeed_jtag *aspeed_jtag) ++{ ++ aspeed_jtag_write(aspeed_jtag, ++ (ASPEED_JTAG_CTL_ENG_EN | ASPEED_JTAG_CTL_ENG_OUT_EN), ++ ASPEED_JTAG_CTRL); ++ ++ aspeed_jtag_write(aspeed_jtag, ++ ASPEED_JTAG_SW_MODE_EN | ASPEED_JTAG_SW_MODE_TDIO, ++ ASPEED_JTAG_SW); ++ aspeed_jtag_write(aspeed_jtag, ++ ASPEED_JTAG_ISR_INST_PAUSE | ++ ASPEED_JTAG_ISR_INST_COMPLETE | ++ ASPEED_JTAG_ISR_DATA_PAUSE | ++ ASPEED_JTAG_ISR_DATA_COMPLETE | ++ ASPEED_JTAG_ISR_INST_PAUSE_EN | ++ ASPEED_JTAG_ISR_INST_COMPLETE_EN | ++ ASPEED_JTAG_ISR_DATA_PAUSE_EN | ++ ASPEED_JTAG_ISR_DATA_COMPLETE_EN, ++ ASPEED_JTAG_ISR); /* Enable Interrupt */ ++} ++ ++static inline void aspeed_jtag_master_26xx(struct aspeed_jtag *aspeed_jtag) ++{ ++ u32 reg_val; ++ ++ reg_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_GBLCTRL) & ++ ASPEED_JTAG_CLK_DIVISOR_MASK; ++ if (aspeed_jtag->mode & JTAG_XFER_HW_MODE) { ++ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_CTRL); ++ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW); ++ } else { ++ aspeed_jtag_write(aspeed_jtag, ++ ASPEED_JTAG_SW_MODE_EN | ++ ASPEED_JTAG_SW_MODE_TDIO, ++ ASPEED_JTAG_SW); + } ++ /* ++ * For the software mode, it's still necessary to enable out_en and ++ * select the out_en in the hw2 register to maintain control of the ++ * TRST bit same as hw2. ++ */ ++ aspeed_jtag_write(aspeed_jtag, ++ reg_val | ASPEED_JTAG_GBLCTRL_ENG_MODE_EN | ++ ASPEED_JTAG_GBLCTRL_ENG_OUT_EN | ++ ASPEED_JTAG_GBLCTRL_TRST, ++ ASPEED_JTAG_GBLCTRL); ++ aspeed_jtag_write(aspeed_jtag, ++ ASPEED_JTAG_INTCTRL_SHCPL_IRQ_EN | ++ ASPEED_JTAG_INTCTRL_SHCPL_IRQ_STAT, ++ ASPEED_JTAG_INTCTRL); /* Enable HW2 IRQ */ + -+ writel(AST2600_I2CC_SET_RX_BUF_LEN(xfer_len), i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL); ++ aspeed_jtag_write(aspeed_jtag, ++ ASPEED_JTAG_ISR_INST_PAUSE | ++ ASPEED_JTAG_ISR_INST_COMPLETE | ++ ASPEED_JTAG_ISR_DATA_PAUSE | ++ ASPEED_JTAG_ISR_DATA_COMPLETE | ++ ASPEED_JTAG_ISR_INST_PAUSE_EN | ++ ASPEED_JTAG_ISR_INST_COMPLETE_EN | ++ ASPEED_JTAG_ISR_DATA_PAUSE_EN | ++ ASPEED_JTAG_ISR_DATA_COMPLETE_EN, ++ ASPEED_JTAG_ISR); /* Enable HW1 Interrupts */ ++} + -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); ++static int aspeed_jtag_mode_set(struct jtag *jtag, struct jtag_mode *jtag_mode) ++{ ++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); + ++ switch (jtag_mode->feature) { ++ case JTAG_XFER_MODE: ++ aspeed_jtag->mode = jtag_mode->mode; ++ aspeed_jtag->llops->master_enable(aspeed_jtag); ++ break; ++ case JTAG_CONTROL_MODE: ++ if (jtag_mode->mode == JTAG_CONTROLLER_OUTPUT_DISABLE) ++ aspeed_jtag->llops->output_disable(aspeed_jtag); ++ else if (jtag_mode->mode == JTAG_CONTROLLER_MODE) ++ aspeed_jtag->llops->master_enable(aspeed_jtag); ++ break; ++ default: ++ return -EINVAL; ++ } + return 0; +} + -+static int ast2600_i2c_setup_byte_rx(u32 cmd, struct ast2600_i2c_bus *i2c_bus) ++/* ++ * We read and write from an unused JTAG Master controller register in SW ++ * mode to create a delay in xfers. ++ * We found this mechanism better than any udelay or usleep option. ++ */ ++static inline void aspeed_jtag_sw_delay_26xx(struct aspeed_jtag *aspeed_jtag) +{ -+ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; ++ u32 read_reg = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_PADCTRL1); + -+ cmd |= AST2600_I2CM_PKT_EN | AST2600_I2CM_RX_CMD; ++ aspeed_jtag_write(aspeed_jtag, read_reg, ASPEED_JTAG_PADCTRL1); ++} + -+ if (cmd & AST2600_I2CM_START_CMD) -+ cmd |= AST2600_I2CM_PKT_ADDR(msg->addr); ++static char aspeed_jtag_tck_cycle(struct aspeed_jtag *aspeed_jtag, u8 tms, ++ u8 tdi) ++{ ++ char tdo = 0; + -+ 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; -+ } ++ /* TCK = 0 */ ++ aspeed_jtag_write(aspeed_jtag, ++ ASPEED_JTAG_SW_MODE_EN | ++ (tms * ASPEED_JTAG_SW_MODE_TMS) | ++ (tdi * ASPEED_JTAG_SW_MODE_TDIO), ++ ASPEED_JTAG_SW); + -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CM_CMD_STS); ++ /* Wait until JTAG Master controller finishes the operation */ ++ if (aspeed_jtag->llops->xfer_sw_delay) ++ aspeed_jtag->llops->xfer_sw_delay(aspeed_jtag); ++ else ++ aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_SW); + -+ return 0; -+} ++ ndelay(aspeed_jtag->tck_period >> 1); + -+static int ast2600_i2c_do_start(struct ast2600_i2c_bus *i2c_bus) -+{ -+ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; ++ /* TCK = 1 */ ++ aspeed_jtag_write(aspeed_jtag, ++ ASPEED_JTAG_SW_MODE_EN | ASPEED_JTAG_SW_MODE_TCK | ++ (tms * ASPEED_JTAG_SW_MODE_TMS) | ++ (tdi * ASPEED_JTAG_SW_MODE_TDIO), ++ ASPEED_JTAG_SW); + -+ /* 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); ++ /* Wait until JTAG Master controller finishes the operation */ ++ if (aspeed_jtag->llops->xfer_sw_delay) ++ aspeed_jtag->llops->xfer_sw_delay(aspeed_jtag); + -+ i2c_bus->controller_xfer_cnt = 0; -+ i2c_bus->buf_index = 0; ++ ndelay(aspeed_jtag->tck_period >> 1); + -+ 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); -+ } ++ if (aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_SW) & ++ ASPEED_JTAG_SW_MODE_TDIO) ++ tdo = 1; ++ ++ return tdo; +} + -+static int ast2700_i2c_irq_err_to_errno(u32 irq_status) ++static int aspeed_jtag_bitbang(struct jtag *jtag, ++ struct bitbang_packet *bitbang, ++ struct tck_bitbang *bitbang_data) +{ -+ 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 aspeed_jtag *aspeed_jtag = jtag_priv(jtag); ++ int i = 0; + ++ for (i = 0; i < bitbang->length; i++) { ++ bitbang_data[i].tdo = ++ aspeed_jtag_tck_cycle(aspeed_jtag, bitbang_data[i].tms, ++ bitbang_data[i].tdi); ++ } + return 0; +} + -+static int ast2600_i2c_irq_err_to_errno(u32 irq_status) ++static inline void aspeed_jtag_xfer_hw_fifo_delay_26xx(void) +{ -+ 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; -+ -+ return 0; ++ udelay(AST26XX_FIFO_UDELAY); +} + -+static void ast2600_i2c_controller_package_irq(struct ast2600_i2c_bus *i2c_bus, u32 sts) ++static int aspeed_jtag_isr_wait(struct aspeed_jtag *aspeed_jtag, u32 bit) +{ -+ struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index]; -+ int xfer_len; -+ int i; -+ -+ 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); -+ -+ sts &= ~(AST2600_I2CM_PKT_DONE | AST2600_I2CM_SW_ISR_MASK); ++ int res = 0; ++ u32 status = 0; ++ u32 iterations = 0; + -+ 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); ++ if (!aspeed_jtag->irq) { ++ res = wait_event_interruptible(aspeed_jtag->jtag_wq, ++ aspeed_jtag->flag & bit); ++ aspeed_jtag->flag &= ~bit; ++ } else { ++ while ((status & bit) == 0) { ++ status = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_ISR); ++#ifdef DEBUG_JTAG ++ dev_dbg(aspeed_jtag->dev, "%s = 0x%08x\n", __func__, ++ status); ++#endif ++ iterations++; ++ if (iterations > WAIT_ITERATIONS) { ++ dev_err(aspeed_jtag->dev, ++ "%s %d in ASPEED_JTAG_ISR\n", ++ "aspeed_jtag driver timed out waiting for bit", ++ bit); ++ res = -EFAULT; ++ break; + } -+ } 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)); -+ } else { -+ xfer_len = 1; -+ } -+ -+ i2c_bus->controller_xfer_cnt += xfer_len; -+ -+ 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); -+ } ++ if ((status & ASPEED_JTAG_ISR_DATA_COMPLETE) == 0) { ++ if (iterations % 25 == 0) ++ usleep_range(1, 5); ++ else ++ udelay(1); + } -+ } 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)); -+ 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)); -+ 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)); + } ++ aspeed_jtag_write(aspeed_jtag, bit | (status & 0xf), ++ ASPEED_JTAG_ISR); ++ } ++ return res; ++} + -+ if (msg->flags & I2C_M_RECV_LEN) { -+ u8 recv_len = 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)); -+ } -+ -+ 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 int aspeed_jtag_wait_shift_complete(struct aspeed_jtag *aspeed_jtag) ++{ ++ int res = 0; ++ u32 status = 0; ++ u32 iterations = 0; + -+ 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); -+ } ++ if (!aspeed_jtag->irq) { ++ res = wait_event_interruptible(aspeed_jtag->jtag_wq, ++ aspeed_jtag->flag & ++ ASPEED_JTAG_INTCTRL_SHCPL_IRQ_STAT); ++ aspeed_jtag->flag &= ~ASPEED_JTAG_INTCTRL_SHCPL_IRQ_STAT; ++ } else { ++ while ((status & ASPEED_JTAG_INTCTRL_SHCPL_IRQ_STAT) == 0) { ++ status = aspeed_jtag_read(aspeed_jtag, ++ ASPEED_JTAG_INTCTRL); ++#ifdef DEBUG_JTAG ++ dev_dbg(aspeed_jtag->dev, "%s = 0x%08x\n", __func__, ++ status); ++#endif ++ iterations++; ++ if (iterations > WAIT_ITERATIONS) { ++ dev_err(aspeed_jtag->dev, ++ "aspeed_jtag driver timed out waiting for shift completed\n"); ++ res = -EFAULT; ++ break; + } -+ } 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); ++ if (iterations % 25 == 0) ++ usleep_range(1, 5); + else -+ ast2600_i2c_setup_byte_rx(0, i2c_bus); ++ udelay(1); + } -+ break; -+ default: -+ dev_dbg(i2c_bus->dev, "unhandled sts %x\n", sts); -+ break; ++ aspeed_jtag_write(aspeed_jtag, ++ ASPEED_JTAG_INTCTRL_SHCPL_IRQ_STAT | ++ ASPEED_JTAG_INTCTRL_SHCPL_IRQ_EN, ++ ASPEED_JTAG_INTCTRL); + } ++ ++ return res; +} + -+static int ast2600_i2c_controller_irq(struct ast2600_i2c_bus *i2c_bus) ++static void aspeed_jtag_set_tap_state(struct aspeed_jtag *aspeed_jtag, ++ enum jtag_tapstate from_state, ++ enum jtag_tapstate end_state) +{ -+ u32 sts = readl(i2c_bus->reg_base + AST2600_I2CM_ISR); -+ u32 ier = readl(i2c_bus->reg_base + AST2600_I2CM_IER); -+ u32 ctrl; ++ int i = 0; ++ enum jtag_tapstate from, to; + -+ /* mask un-used isr bits */ -+ sts &= ~AST2600_I2CM_ISR_MASK; ++ from = from_state; ++ to = end_state; + -+ if (!i2c_bus->alert_enable) -+ sts &= ~AST2600_I2CM_SMBUS_ALT; ++ for (i = 0; i < _tms_cycle_lookup[from][to].count; i++) ++ aspeed_jtag_tck_cycle(aspeed_jtag, ++ ((_tms_cycle_lookup[from][to].tmsbits ++ >> i) & 0x1), 0); ++ aspeed_jtag->current_state = end_state; ++} + -+ 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; -+ } ++static void aspeed_jtag_set_tap_state_sw(struct aspeed_jtag *aspeed_jtag, ++ struct jtag_tap_state *tapstate) ++{ ++ int i; + -+ 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; ++ /* SW mode from curent tap state -> to end_state */ ++ if (tapstate->reset || tapstate->endstate == JTAG_STATE_TLRESET) { ++ for (i = 0; i < ASPEED_JTAG_RESET_CNTR; i++) ++ aspeed_jtag_tck_cycle(aspeed_jtag, 1, 0); ++ aspeed_jtag->current_state = JTAG_STATE_TLRESET; + } + -+ 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; -+ } -+ } ++ aspeed_jtag_set_tap_state(aspeed_jtag, tapstate->from, ++ tapstate->endstate); ++ if (tapstate->endstate == JTAG_STATE_TLRESET || ++ tapstate->endstate == JTAG_STATE_IDLE || ++ tapstate->endstate == JTAG_STATE_PAUSEDR || ++ tapstate->endstate == JTAG_STATE_PAUSEIR) ++ for (i = 0; i < tapstate->tck; i++) ++ aspeed_jtag_tck_cycle(aspeed_jtag, 0, 0); ++} + -+ /* 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; -+ } ++static int aspeed_jtag_status_set(struct jtag *jtag, ++ struct jtag_tap_state *tapstate) ++{ ++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); ++ int i; ++ ++ if (tapstate->from == JTAG_STATE_CURRENT) ++ tapstate->from = aspeed_jtag->current_state; ++ if (tapstate->endstate == JTAG_STATE_CURRENT) ++ tapstate->endstate = aspeed_jtag->current_state; ++#ifdef DEBUG_JTAG ++ dev_dbg(aspeed_jtag->dev, "Set TAP state: %s\n", ++ end_status_str[tapstate->endstate]); ++#endif ++ ++ if (!(aspeed_jtag->mode & JTAG_XFER_HW_MODE)) { ++ aspeed_jtag_set_tap_state_sw(aspeed_jtag, tapstate); ++ return 0; + } + -+ if (AST2600_I2CM_PKT_DONE & sts) { -+ ast2600_i2c_controller_package_irq(i2c_bus, sts); -+ return 1; ++ /* x TMS high + 1 TMS low */ ++ if (tapstate->reset) { ++ /* Disable sw mode */ ++ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW); ++ mdelay(1); ++ aspeed_jtag_write(aspeed_jtag, ++ ASPEED_JTAG_CTL_ENG_EN | ++ ASPEED_JTAG_CTL_ENG_OUT_EN | ++ ASPEED_JTAG_CTL_FORCE_TMS, ++ ASPEED_JTAG_CTRL); ++ mdelay(1); ++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_TDIO, ++ ASPEED_JTAG_SW); ++ aspeed_jtag->current_state = JTAG_STATE_TLRESET; + } ++ for (i = 0; i < tapstate->tck; i++) ++ ndelay(aspeed_jtag->tck_period); + + return 0; +} + -+static irqreturn_t ast2600_i2c_bus_irq(int irq, void *dev_id) ++static int aspeed_jtag_shctrl_tms_mask(enum jtag_tapstate from, ++ enum jtag_tapstate to, ++ enum jtag_tapstate there, ++ enum jtag_tapstate endstate, ++ u32 start_shift, u32 end_shift, ++ u32 *tms_mask) +{ -+ struct ast2600_i2c_bus *i2c_bus = dev_id; ++ u32 pre_tms = start_shift ? _tms_cycle_lookup[from][to].count : 0; ++ u32 post_tms = end_shift ? _tms_cycle_lookup[there][endstate].count : 0; ++ u32 tms_value = start_shift ? _tms_cycle_lookup[from][to].tmsbits : 0; + -+#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; ++ tms_value |= end_shift ? _tms_cycle_lookup[there][endstate].tmsbits ++ << pre_tms : ++ 0; ++ if (pre_tms > GENMASK(2, 0) || post_tms > GENMASK(2, 0)) { ++ pr_err("pre/port tms count is greater than hw limit"); ++ return -EINVAL; + } -+#endif -+ return IRQ_RETVAL(ast2600_i2c_controller_irq(i2c_bus)); ++ *tms_mask = start_shift | ASPEED_JTAG_SHCTRL_PRE_TMS(pre_tms) | ++ end_shift | ASPEED_JTAG_SHCTRL_POST_TMS(post_tms) | ++ ASPEED_JTAG_SHCTRL_TMS(tms_value); ++ return 0; +} + -+static int ast2600_i2c_controller_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) ++static void aspeed_jtag_set_tap_state_hw2(struct aspeed_jtag *aspeed_jtag, ++ struct jtag_tap_state *tapstate) +{ -+ struct ast2600_i2c_bus *i2c_bus = i2c_get_adapdata(adap); -+ unsigned long timeout; -+ int ret; ++ u32 reg_val, execute_tck; ++ u32 tck = tapstate->tck; + -+ 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; ++ /* x TMS high + 1 TMS low */ ++ if (tapstate->reset || tapstate->endstate == JTAG_STATE_TLRESET) { ++ /* Disable sw mode */ ++ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW); ++ udelay(AST26XX_JTAG_CTRL_UDELAY); ++ reg_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_GBLCTRL); ++ aspeed_jtag_write(aspeed_jtag, ++ reg_val | ASPEED_JTAG_GBLCTRL_ENG_MODE_EN | ++ ASPEED_JTAG_GBLCTRL_ENG_OUT_EN | ++ ASPEED_JTAG_GBLCTRL_RESET_FIFO | ++ ASPEED_JTAG_GBLCTRL_FORCE_TMS, ++ ASPEED_JTAG_GBLCTRL); ++ udelay(AST26XX_JTAG_CTRL_UDELAY); ++ while (aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_GBLCTRL) & ASPEED_JTAG_GBLCTRL_FORCE_TMS) ++ ; ++ aspeed_jtag->current_state = JTAG_STATE_TLRESET; ++ } else { ++ aspeed_jtag_set_tap_state(aspeed_jtag, ++ aspeed_jtag->current_state, ++ tapstate->endstate); + } ++ /* Run TCK */ ++ while (tck) { ++ execute_tck = tck > GENMASK(9, 0) ? GENMASK(9, 0) : tck; ++ /* Disable sw mode */ ++ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW); ++ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_PADCTRL0); ++ reg_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_GBLCTRL); ++ reg_val = reg_val & ~(GENMASK(22, 20)); ++ aspeed_jtag_write(aspeed_jtag, ++ reg_val | ASPEED_JTAG_GBLCTRL_FIFO_CTRL_MODE | ++ ASPEED_JTAG_GBLCTRL_STSHIFT(0) | ++ ASPEED_JTAG_GBLCTRL_UPDT_SHIFT(execute_tck), ++ ASPEED_JTAG_GBLCTRL); + -+#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; -+ } ++ aspeed_jtag_write(aspeed_jtag, ++ ASPEED_JTAG_SHCTRL_STSHIFT_EN | ++ ASPEED_JTAG_SHCTRL_LWRDT_SHIFT(execute_tck), ++ ASPEED_JTAG_SHCTRL); ++ aspeed_jtag_wait_shift_complete(aspeed_jtag); ++ tck -= execute_tck; + } -+#endif ++} + -+ 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); ++static int aspeed_jtag_status_set_26xx(struct jtag *jtag, ++ struct jtag_tap_state *tapstate) ++{ ++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); ++ ++ if (tapstate->from == JTAG_STATE_CURRENT) ++ tapstate->from = aspeed_jtag->current_state; ++ if (tapstate->endstate == JTAG_STATE_CURRENT) ++ tapstate->endstate = aspeed_jtag->current_state; ++#ifdef DEBUG_JTAG ++ dev_dbg(aspeed_jtag->dev, "Set TAP state: status %s from %s to %s\n", ++ end_status_str[aspeed_jtag->current_state], ++ end_status_str[tapstate->from], ++ end_status_str[tapstate->endstate]); +#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); + -+ 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); -+ 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; ++ if (!(aspeed_jtag->mode & JTAG_XFER_HW_MODE)) { ++ aspeed_jtag_set_tap_state_sw(aspeed_jtag, tapstate); ++ return 0; + } + -+ dev_dbg(i2c_bus->dev, "bus%d-m: %d end\n", i2c_bus->adap.nr, i2c_bus->cmd_err); -+ -+controller_out: -+ return ret; ++ aspeed_jtag_set_tap_state_hw2(aspeed_jtag, tapstate); ++ return 0; +} + -+static int ast2600_i2c_init(struct ast2600_i2c_bus *i2c_bus) ++static void aspeed_jtag_xfer_sw(struct aspeed_jtag *aspeed_jtag, ++ struct jtag_xfer *xfer, u32 *data) +{ -+ 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); -+ -+ i2c_bus->multi_master = device_property_read_bool(&pdev->dev, "multi-master"); -+ 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", -+ &i2c_bus->debounce_level)) { -+ u32 debounce_level = 0; ++ unsigned long remain_xfer = xfer->length; ++ unsigned long shift_bits = 0; ++ unsigned long index = 0; ++ unsigned long tdi; ++ char tdo; + -+ /* 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; -+ } ++#ifdef DEBUG_JTAG ++ dev_dbg(aspeed_jtag->dev, "SW JTAG SHIFT %s, length = %d\n", ++ (xfer->type == JTAG_SIR_XFER) ? "IR" : "DR", xfer->length); ++#endif + -+ debounce_level = readl(i2c_bus->reg_base + MSIC2_CONFIG) -+ & ~(AST2700_DEBOUNCE_MASK); ++ if (xfer->type == JTAG_SIR_XFER) ++ aspeed_jtag_set_tap_state(aspeed_jtag, xfer->from, ++ JTAG_STATE_SHIFTIR); ++ else ++ aspeed_jtag_set_tap_state(aspeed_jtag, xfer->from, ++ JTAG_STATE_SHIFTDR); + -+ debounce_level |= i2c_bus->debounce_level; -+ writel(debounce_level, i2c_bus->reg_base + MSIC2_CONFIG); ++ tdi = ASPEED_JTAG_GET_TDI(xfer->direction, data[index]); ++ data[index] = 0; ++ while (remain_xfer > 1) { ++ tdo = aspeed_jtag_tck_cycle(aspeed_jtag, 0, ++ tdi & ASPEED_JTAG_DATA_MSB); ++ data[index] |= tdo ++ << (shift_bits % ASPEED_JTAG_DATA_CHUNK_SIZE); ++ tdi >>= 1; ++ shift_bits++; ++ remain_xfer--; + -+ fun_ctrl |= AST2700_I2CC_MANUAL_DEBOUNCE; ++ if (shift_bits % ASPEED_JTAG_DATA_CHUNK_SIZE == 0) { ++ tdo = 0; ++ index++; ++ tdi = ASPEED_JTAG_GET_TDI(xfer->direction, data[index]); ++ data[index] = 0; + } + } + -+ /* 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); -+ -+ 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); ++ if ((xfer->endstate == (xfer->type == JTAG_SIR_XFER ? ++ JTAG_STATE_SHIFTIR : ++ JTAG_STATE_SHIFTDR))) { ++ /* Stay in Shift IR/DR*/ ++ tdo = aspeed_jtag_tck_cycle(aspeed_jtag, 0, ++ tdi & ASPEED_JTAG_DATA_MSB); ++ data[index] |= tdo ++ << (shift_bits % ASPEED_JTAG_DATA_CHUNK_SIZE); ++ } else { ++ /* Goto end state */ ++ tdo = aspeed_jtag_tck_cycle(aspeed_jtag, 1, ++ tdi & ASPEED_JTAG_DATA_MSB); ++ data[index] |= tdo ++ << (shift_bits % ASPEED_JTAG_DATA_CHUNK_SIZE); ++ aspeed_jtag->status = (xfer->type == JTAG_SIR_XFER) ? ++ JTAG_STATE_EXIT1IR : ++ JTAG_STATE_EXIT1DR; ++ aspeed_jtag_set_tap_state(aspeed_jtag, aspeed_jtag->status, ++ xfer->endstate); + } ++} + -+ /* Clear Interrupt */ -+ writel(GENMASK(27, 0), i2c_bus->reg_base + AST2600_I2CM_ISR); ++static int aspeed_jtag_xfer_push_data_26xx(struct aspeed_jtag *aspeed_jtag, ++ enum jtag_xfer_type type, ++ u32 bits_len) ++{ ++ int res = 0; + -+#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; ++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_TRANS_LEN(bits_len), ++ ASPEED_JTAG_CTRL); ++ if (type == JTAG_SIR_XFER) { ++ aspeed_jtag_write(aspeed_jtag, ++ ASPEED_JTAG_TRANS_LEN(bits_len) | ++ ASPEED_JTAG_CTL_26XX_INST_EN, ++ ASPEED_JTAG_CTRL); ++ res = aspeed_jtag_isr_wait(aspeed_jtag, ++ ASPEED_JTAG_ISR_INST_PAUSE); ++ } else { ++ aspeed_jtag_write(aspeed_jtag, ++ ASPEED_JTAG_TRANS_LEN(bits_len) | ++ ASPEED_JTAG_CTL_DATA_EN, ++ ASPEED_JTAG_CTRL); ++ res = aspeed_jtag_isr_wait(aspeed_jtag, ++ ASPEED_JTAG_ISR_DATA_PAUSE); + } ++ return res; ++} + -+ 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 -+ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_IER); -+#endif ++static int aspeed_jtag_xfer_push_data(struct aspeed_jtag *aspeed_jtag, ++ enum jtag_xfer_type type, u32 bits_len) ++{ ++ int res = 0; + -+ return 0; ++ if (type == JTAG_SIR_XFER) { ++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_IOUT_LEN(bits_len), ++ ASPEED_JTAG_CTRL); ++ aspeed_jtag_write(aspeed_jtag, ++ ASPEED_JTAG_IOUT_LEN(bits_len) | ++ ASPEED_JTAG_CTL_INST_EN, ++ ASPEED_JTAG_CTRL); ++ res = aspeed_jtag_isr_wait(aspeed_jtag, ++ ASPEED_JTAG_ISR_INST_PAUSE); ++ } else { ++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_DOUT_LEN(bits_len), ++ ASPEED_JTAG_CTRL); ++ aspeed_jtag_write(aspeed_jtag, ++ ASPEED_JTAG_DOUT_LEN(bits_len) | ++ ASPEED_JTAG_CTL_DATA_EN, ++ ASPEED_JTAG_CTRL); ++ res = aspeed_jtag_isr_wait(aspeed_jtag, ++ ASPEED_JTAG_ISR_DATA_PAUSE); ++ } ++ return res; +} + -+#if IS_ENABLED(CONFIG_I2C_SLAVE) -+static int ast2600_i2c_reg_target(struct i2c_client *client) ++static int aspeed_jtag_xfer_push_data_last_26xx(struct aspeed_jtag *aspeed_jtag, ++ enum jtag_xfer_type type, ++ u32 shift_bits) +{ -+ 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; -+ -+ /* check target client input and target counts*/ -+ if (!client || i2c_bus->target_attached == AST2600_I2C_TARGET_COUNT) -+ return -EINVAL; ++ int res = 0; + -+ /* 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; -+ } -+ } ++ aspeed_jtag_write(aspeed_jtag, ++ ASPEED_JTAG_TRANS_LEN(shift_bits) | ++ ASPEED_JTAG_CTL_26XX_LASPEED_TRANS, ++ ASPEED_JTAG_CTRL); ++ if (type == JTAG_SIR_XFER) { ++ aspeed_jtag_write(aspeed_jtag, ++ ASPEED_JTAG_TRANS_LEN(shift_bits) | ++ ASPEED_JTAG_CTL_26XX_LASPEED_TRANS | ++ ASPEED_JTAG_CTL_26XX_INST_EN, ++ ASPEED_JTAG_CTRL); ++ res = aspeed_jtag_isr_wait(aspeed_jtag, ++ ASPEED_JTAG_ISR_INST_COMPLETE); ++ } else { ++ aspeed_jtag_write(aspeed_jtag, ++ ASPEED_JTAG_TRANS_LEN(shift_bits) | ++ ASPEED_JTAG_CTL_26XX_LASPEED_TRANS | ++ ASPEED_JTAG_CTL_DATA_EN, ++ ASPEED_JTAG_CTRL); ++ res = aspeed_jtag_isr_wait(aspeed_jtag, ++ ASPEED_JTAG_ISR_DATA_COMPLETE); + } ++ return res; ++} + -+ /* 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; -+ } ++static int aspeed_jtag_xfer_push_data_last(struct aspeed_jtag *aspeed_jtag, ++ enum jtag_xfer_type type, ++ u32 shift_bits) ++{ ++ int res = 0; + -+ /* Set target addr. */ -+ writel(target_addr, i2c_bus->reg_base + AST2600_I2CS_ADDR_CTRL); -+ break; -+ } ++ if (type == JTAG_SIR_XFER) { ++ aspeed_jtag_write(aspeed_jtag, ++ ASPEED_JTAG_IOUT_LEN(shift_bits) | ++ ASPEED_JTAG_CTL_LASPEED_INST, ++ ASPEED_JTAG_CTRL); ++ aspeed_jtag_write(aspeed_jtag, ++ ASPEED_JTAG_IOUT_LEN(shift_bits) | ++ ASPEED_JTAG_CTL_LASPEED_INST | ++ ASPEED_JTAG_CTL_INST_EN, ++ ASPEED_JTAG_CTRL); ++ res = aspeed_jtag_isr_wait(aspeed_jtag, ++ ASPEED_JTAG_ISR_INST_COMPLETE); ++ } else { ++ aspeed_jtag_write(aspeed_jtag, ++ ASPEED_JTAG_DOUT_LEN(shift_bits) | ++ ASPEED_JTAG_CTL_LASPEED_DATA, ++ ASPEED_JTAG_CTRL); ++ aspeed_jtag_write(aspeed_jtag, ++ ASPEED_JTAG_DOUT_LEN(shift_bits) | ++ ASPEED_JTAG_CTL_LASPEED_DATA | ++ ASPEED_JTAG_CTL_DATA_EN, ++ ASPEED_JTAG_CTRL); ++ res = aspeed_jtag_isr_wait(aspeed_jtag, ++ ASPEED_JTAG_ISR_DATA_COMPLETE); + } ++ return res; ++} + -+ /* don't reg target */ -+ if (!target_reg) -+ return -EINVAL; -+ -+ dev_dbg(i2c_bus->dev, "target addr %x\n", client->addr); ++static int aspeed_jtag_xfer_hw(struct aspeed_jtag *aspeed_jtag, ++ struct jtag_xfer *xfer, u32 *data) ++{ ++ unsigned long remain_xfer = xfer->length; ++ unsigned long index = 0; ++ char shift_bits; ++ u32 data_reg; ++ u32 scan_end; ++ union pad_config padding; ++ int retval = 0; + -+ /* turn on target mode */ -+ if (!(ctrl & AST2600_I2CC_SLAVE_EN)) { -+ writel(ctrl | AST2600_I2CC_SLAVE_EN, -+ i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); -+ } ++ padding.int_value = xfer->padding; + -+ /* 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) -+ cmd |= AST2600_I2CS_RX_DMA_EN; ++#ifdef DEBUG_JTAG ++ dev_dbg(aspeed_jtag->dev, "HW JTAG SHIFT %s, length = %d pad = 0x%x\n", ++ (xfer->type == JTAG_SIR_XFER) ? "IR" : "DR", xfer->length, ++ xfer->padding); ++#endif ++ data_reg = xfer->type == JTAG_SIR_XFER ? ASPEED_JTAG_INST : ++ ASPEED_JTAG_DATA; ++ if (xfer->endstate == JTAG_STATE_SHIFTIR || ++ xfer->endstate == JTAG_STATE_SHIFTDR || ++ xfer->endstate == JTAG_STATE_PAUSEIR || ++ xfer->endstate == JTAG_STATE_PAUSEDR) { ++ scan_end = 0; + } else { -+ cmd &= ~AST2600_I2CS_PKT_MODE_EN; ++ if (padding.post_pad_number) ++ scan_end = 0; ++ else ++ scan_end = 1; + } + -+ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS); -+ -+ i2c_bus->target_attached++; -+ return 0; -+} ++ /* Perform pre padding */ ++ if (padding.pre_pad_number) { ++ struct jtag_xfer pre_xfer = { ++ .type = xfer->type, ++ .direction = JTAG_WRITE_XFER, ++ .from = xfer->from, ++ .endstate = xfer->type == JTAG_SIR_XFER ? ++ JTAG_STATE_SHIFTIR : JTAG_STATE_SHIFTDR, ++ .padding = 0, ++ .length = padding.pre_pad_number, ++ }; ++ if (padding.pre_pad_number > ASPEED_JTAG_MAX_PAD_SIZE) ++ return -EINVAL; ++ retval = aspeed_jtag_xfer_hw(aspeed_jtag, &pre_xfer, ++ padding.pad_data ? ++ aspeed_jtag->pad_data_one : ++ aspeed_jtag->pad_data_zero); ++ if (retval) ++ return retval; ++ } + -+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; ++ while (remain_xfer) { ++ if (xfer->direction & JTAG_WRITE_XFER) ++ aspeed_jtag_write(aspeed_jtag, data[index], data_reg); ++ else ++ aspeed_jtag_write(aspeed_jtag, 0, data_reg); ++ if (aspeed_jtag->llops->xfer_hw_fifo_delay) ++ aspeed_jtag->llops->xfer_hw_fifo_delay(); + -+ /* check target client input and salve counts*/ -+ if (!client || i2c_bus->target_attached == 0) -+ return -EINVAL; ++ if (remain_xfer > ASPEED_JTAG_DATA_CHUNK_SIZE) { ++#ifdef DEBUG_JTAG ++ dev_dbg(aspeed_jtag->dev, ++ "Chunk len=%d chunk_size=%d remain_xfer=%lu\n", ++ xfer->length, ASPEED_JTAG_DATA_CHUNK_SIZE, ++ remain_xfer); ++#endif ++ shift_bits = ASPEED_JTAG_DATA_CHUNK_SIZE; + -+ /* 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; ++ /* ++ * Transmit bytes that were not equals to column length ++ * and after the transfer go to Pause IR/DR. ++ */ ++ if (aspeed_jtag->llops->xfer_push_data(aspeed_jtag, ++ xfer->type, ++ shift_bits) ++ != 0) { ++ return -EFAULT; ++ } ++ } else { ++ /* ++ * Read bytes equals to column length ++ */ ++ shift_bits = remain_xfer; ++ if (scan_end) { ++ /* ++ * If this data is the end of the transmission ++ * send remaining bits and go to endstate ++ */ ++#ifdef DEBUG_JTAG ++ dev_dbg(aspeed_jtag->dev, ++ "Last len=%d chunk_size=%d remain_xfer=%lu\n", ++ xfer->length, ++ ASPEED_JTAG_DATA_CHUNK_SIZE, ++ remain_xfer); ++#endif ++ if (aspeed_jtag->llops->xfer_push_data_last( ++ aspeed_jtag, xfer->type, ++ shift_bits) != 0) { ++ return -EFAULT; ++ } ++ } else { ++ /* ++ * If transmission is waiting for additional ++ * data send remaining bits and then go to ++ * Pause IR/DR. ++ */ ++#ifdef DEBUG_JTAG ++ dev_dbg(aspeed_jtag->dev, ++ "Tail len=%d chunk_size=%d remain_xfer=%lu\n", ++ xfer->length, ++ ASPEED_JTAG_DATA_CHUNK_SIZE, ++ remain_xfer); ++#endif ++ if (aspeed_jtag->llops->xfer_push_data( ++ aspeed_jtag, xfer->type, ++ shift_bits) != 0) { ++ return -EFAULT; ++ } + } + } -+ } + -+ /* don't un-reg target */ -+ if (!target_unreg) -+ return -EINVAL; ++ if (xfer->direction & JTAG_READ_XFER) { ++ if (shift_bits < ASPEED_JTAG_DATA_CHUNK_SIZE) { ++ data[index] = ++ aspeed_jtag_read(aspeed_jtag, data_reg); + -+ i2c_bus->target_attached--; ++ data[index] >>= ASPEED_JTAG_DATA_CHUNK_SIZE - ++ shift_bits; ++ } else { ++ data[index] = ++ aspeed_jtag_read(aspeed_jtag, data_reg); ++ } ++ if (aspeed_jtag->llops->xfer_hw_fifo_delay) ++ aspeed_jtag->llops->xfer_hw_fifo_delay(); ++ } + -+ /* 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); ++ remain_xfer = remain_xfer - shift_bits; ++ index++; + } + ++ /* Perform post padding */ ++ if (padding.post_pad_number) { ++ struct jtag_xfer post_xfer = { ++ .type = xfer->type, ++ .direction = JTAG_WRITE_XFER, ++ .from = xfer->from, ++ .endstate = xfer->endstate, ++ .padding = 0, ++ .length = padding.post_pad_number, ++ }; ++ if (padding.post_pad_number > ASPEED_JTAG_MAX_PAD_SIZE) ++ return -EINVAL; ++ retval = aspeed_jtag_xfer_hw(aspeed_jtag, &post_xfer, ++ padding.pad_data ? ++ aspeed_jtag->pad_data_one : ++ aspeed_jtag->pad_data_zero); ++ if (retval) ++ return retval; ++ } + return 0; +} -+#endif -+ -+static u32 ast2600_i2c_functionality(struct i2c_adapter *adap) -+{ -+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA; -+} -+ -+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 -+}; + -+static int ast2600_i2c_probe(struct platform_device *pdev) ++static int aspeed_jtag_xfer(struct jtag *jtag, struct jtag_xfer *xfer, ++ u8 *xfer_data) +{ -+ 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; ++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); + -+ i2c_bus->version = (enum i2c_version)device_get_match_data(dev); ++ if (!(aspeed_jtag->mode & JTAG_XFER_HW_MODE)) { ++ /* SW mode */ ++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_TDIO, ++ ASPEED_JTAG_SW); + -+ i2c_bus->reg_base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(i2c_bus->reg_base)) -+ return PTR_ERR(i2c_bus->reg_base); ++ aspeed_jtag->llops->xfer_sw(aspeed_jtag, xfer, ++ (u32 *)xfer_data); ++ } else { ++ /* HW mode */ ++ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW); ++ if (aspeed_jtag->llops->xfer_hw(aspeed_jtag, xfer, ++ (u32 *)xfer_data) != 0) ++ return -EFAULT; ++ } + -+ 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"); ++ aspeed_jtag->status = xfer->endstate; ++ return 0; ++} + -+ reset_control_deassert(i2c_bus->rst); ++static int aspeed_jtag_xfer_hw2(struct aspeed_jtag *aspeed_jtag, ++ struct jtag_xfer *xfer, u32 *data) ++{ ++ unsigned long remain_xfer = xfer->length; ++ unsigned long partial_xfer_size = 0; ++ unsigned long index = 0; ++ u32 shift_bits; ++ u32 data_reg; ++ u32 reg_val; ++ enum jtag_tapstate shift; ++ enum jtag_tapstate exit; ++ enum jtag_tapstate exitx; ++ enum jtag_tapstate pause; ++ enum jtag_tapstate endstate; ++ u32 start_shift; ++ u32 end_shift; ++ u32 tms_mask; ++ int ret; + -+ 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); ++ if (xfer->type == JTAG_SIR_XFER) { ++ data_reg = ASPEED_JTAG_SHDATA; ++ shift = JTAG_STATE_SHIFTIR; ++ pause = JTAG_STATE_PAUSEIR; ++ exit = JTAG_STATE_EXIT1IR; ++ exitx = JTAG_STATE_EXIT1DR; ++ } else { ++ data_reg = ASPEED_JTAG_SHDATA; ++ shift = JTAG_STATE_SHIFTDR; ++ pause = JTAG_STATE_PAUSEDR; ++ exit = JTAG_STATE_EXIT1DR; ++ exitx = JTAG_STATE_EXIT1IR; ++ } ++#ifdef DEBUG_JTAG ++ dev_dbg(aspeed_jtag->dev, ++ "HW2 JTAG SHIFT %s, length %d status %s from %s to %s then %s pad 0x%x\n", ++ (xfer->type == JTAG_SIR_XFER) ? "IR" : "DR", xfer->length, ++ end_status_str[aspeed_jtag->current_state], ++ end_status_str[xfer->from], ++ end_status_str[shift], ++ end_status_str[xfer->endstate], xfer->padding); ++#endif + -+ 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 (aspeed_jtag->current_state == shift) { ++ start_shift = 0; ++ } else { ++ start_shift = ASPEED_JTAG_SHCTRL_START_SHIFT; + } + -+#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; ++ if (xfer->endstate == shift) { ++ /* ++ * In the case of shifting 1 bit of data and attempting to stay ++ * in the SHIFT state, the AST2600 JTAG Master Controller in ++ * Hardware mode 2 has been observed to go to EXIT1 IR/DR ++ * instead of staying in the SHIFT IR/DR state. The following ++ * code special cases this one bit shift and directs the state ++ * machine to go to the PAUSE IR/DR state instead. ++ * Alternatively, the application making driver calls can avoid ++ * this situation as follows: ++ * 1.) Bundle all of the shift bits together into one call ++ * AND/OR ++ * 2.) Direct all partial shifts to move to the PAUSE-IR/DR ++ * state. ++ */ ++ if (xfer->length == 1) { ++#ifdef DEBUG_JTAG ++ dev_warn(aspeed_jtag->dev, "JTAG Silicon WA: going to pause instead of shift"); +#endif -+ i2c_bus->dev = dev; -+ if (i2c_bus->version == AST2600) { -+ i2c_bus->mode = BUFF_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; -+ } -+ -+ 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; ++ end_shift = ASPEED_JTAG_SHCTRL_END_SHIFT; ++ endstate = pause; ++ } else { ++ end_shift = 0; ++ endstate = shift; + } + } else { -+ i2c_bus->mode = DMA_MODE; ++ endstate = xfer->endstate; ++ end_shift = ASPEED_JTAG_SHCTRL_END_SHIFT; + } + -+ /* -+ * 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; ++ aspeed_jtag_write(aspeed_jtag, xfer->padding, ASPEED_JTAG_PADCTRL0); + -+ if (!i2c_bus->timeout) -+ i2c_bus->timeout = 1; -+ } ++ while (remain_xfer) { ++ unsigned long partial_xfer; ++ unsigned long partial_index; + -+ init_completion(&i2c_bus->cmd_complete); ++ if (remain_xfer > ASPEED_JTAG_HW2_DATA_CHUNK_SIZE) ++ partial_xfer_size = ASPEED_JTAG_HW2_DATA_CHUNK_SIZE; ++ else ++ partial_xfer_size = remain_xfer; + -+ i2c_bus->irq = platform_get_irq(pdev, 0); -+ if (i2c_bus->irq < 0) -+ return i2c_bus->irq; ++ partial_index = index; ++ partial_xfer = partial_xfer_size; + -+ platform_set_drvdata(pdev, i2c_bus); ++ reg_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_GBLCTRL); ++ aspeed_jtag_write(aspeed_jtag, reg_val | ++ ASPEED_JTAG_GBLCTRL_RESET_FIFO, ++ ASPEED_JTAG_GBLCTRL); + -+ 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"); ++ /* Switch internal FIFO into CPU mode */ ++ reg_val = reg_val & ~BIT(24); ++ aspeed_jtag_write(aspeed_jtag, reg_val, ++ ASPEED_JTAG_GBLCTRL); + -+ i2c_bus->apb_clk = clk_get_rate(i2c_bus->clk); ++ while (partial_xfer) { ++ if (partial_xfer > ASPEED_JTAG_DATA_CHUNK_SIZE) ++ shift_bits = ASPEED_JTAG_DATA_CHUNK_SIZE; ++ else ++ shift_bits = partial_xfer; + -+ i2c_parse_fw_timings(i2c_bus->dev, &i2c_bus->timing_info, true); ++ if (xfer->direction & JTAG_WRITE_XFER) ++ aspeed_jtag_write(aspeed_jtag, ++ data[partial_index++], ++ data_reg); ++ else ++ aspeed_jtag_write(aspeed_jtag, 0, data_reg); ++ if (aspeed_jtag->llops->xfer_hw_fifo_delay) ++ aspeed_jtag->llops->xfer_hw_fifo_delay(); ++ partial_xfer = partial_xfer - shift_bits; ++ } ++ if (remain_xfer > ASPEED_JTAG_HW2_DATA_CHUNK_SIZE) { ++ shift_bits = ASPEED_JTAG_HW2_DATA_CHUNK_SIZE; + -+ /* 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)); ++ /* ++ * Transmit bytes that were not equals to column length ++ * and after the transfer go to Pause IR/DR. ++ */ + -+ ret = ast2600_i2c_init(i2c_bus); -+ if (ret < 0) -+ return dev_err_probe(dev, ret, "Unable to initial i2c %d\n", ret); ++ ret = aspeed_jtag_shctrl_tms_mask(aspeed_jtag->current_state, shift, exit, ++ endstate, start_shift, 0, &tms_mask); ++ if (ret) ++ return ret; + -+ 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); ++ reg_val = aspeed_jtag_read(aspeed_jtag, ++ ASPEED_JTAG_GBLCTRL); ++ reg_val = reg_val & ~(GENMASK(22, 20)); ++ aspeed_jtag_write(aspeed_jtag, reg_val | ++ ASPEED_JTAG_GBLCTRL_FIFO_CTRL_MODE | ++ ASPEED_JTAG_GBLCTRL_UPDT_SHIFT( ++ shift_bits), ++ ASPEED_JTAG_GBLCTRL); + -+ /* Set interrupt generation of i2c controller */ -+ writel(AST2600_I2CM_PKT_DONE | AST2600_I2CM_BUS_RECOVER, -+ i2c_bus->reg_base + AST2600_I2CM_IER); ++ aspeed_jtag_write(aspeed_jtag, tms_mask | ++ ASPEED_JTAG_SHCTRL_LWRDT_SHIFT(shift_bits), ++ ASPEED_JTAG_SHCTRL); ++ aspeed_jtag_wait_shift_complete(aspeed_jtag); ++ } else { ++ /* ++ * Read bytes equals to column length ++ */ ++ shift_bits = remain_xfer; ++ ret = aspeed_jtag_shctrl_tms_mask(aspeed_jtag->current_state, shift, exit, ++ endstate, start_shift, end_shift, ++ &tms_mask); ++ if (ret) ++ return ret; + -+ ret = devm_i2c_add_adapter(dev, &i2c_bus->adap); -+ if (ret) -+ return ret; ++ reg_val = aspeed_jtag_read(aspeed_jtag, ++ ASPEED_JTAG_GBLCTRL); ++ reg_val = reg_val & ~(GENMASK(22, 20)); ++ aspeed_jtag_write(aspeed_jtag, reg_val | ++ ASPEED_JTAG_GBLCTRL_FIFO_CTRL_MODE | ++ ASPEED_JTAG_GBLCTRL_UPDT_SHIFT( ++ shift_bits), ++ ASPEED_JTAG_GBLCTRL); + -+ 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; -+ } ++ aspeed_jtag_write(aspeed_jtag, tms_mask | ++ ASPEED_JTAG_SHCTRL_LWRDT_SHIFT( ++ shift_bits), ++ ASPEED_JTAG_SHCTRL); + -+ 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); ++ aspeed_jtag_wait_shift_complete(aspeed_jtag); ++ } ++ ++ partial_index = index; ++ partial_xfer = partial_xfer_size; ++ while (partial_xfer) { ++ if (partial_xfer > ++ ASPEED_JTAG_DATA_CHUNK_SIZE) { ++ shift_bits = ++ ASPEED_JTAG_DATA_CHUNK_SIZE; ++ data[partial_index++] = ++ aspeed_jtag_read(aspeed_jtag, ++ data_reg); ++ ++ } else { ++ shift_bits = partial_xfer; ++ data[partial_index++] = ++ aspeed_jtag_read(aspeed_jtag, ++ data_reg); ++ } ++ if (aspeed_jtag->llops->xfer_hw_fifo_delay) ++ aspeed_jtag->llops->xfer_hw_fifo_delay(); ++ partial_xfer = partial_xfer - shift_bits; ++ } + ++ remain_xfer = remain_xfer - partial_xfer_size; ++ index = partial_index; ++ start_shift = 0; ++ } ++ aspeed_jtag->current_state = endstate; + return 0; +} + -+static void ast2600_i2c_remove(struct platform_device *pdev) ++static int aspeed_jtag_status_get(struct jtag *jtag, u32 *status) +{ -+ struct ast2600_i2c_bus *i2c_bus = platform_get_drvdata(pdev); ++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); + -+ /* Disable everything. */ -+ writel(0, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL); -+ writel(0, i2c_bus->reg_base + AST2600_I2CM_IER); ++ *status = aspeed_jtag->current_state; ++ return 0; +} + -+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); -+ -+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, -+ }, -+}; -+ -+module_platform_driver(ast2600_i2c_bus_driver); -+ -+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 2026-04-08 18:03:48.267706106 +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) ++static irqreturn_t aspeed_jtag_interrupt(s32 this_irq, void *dev_id) ++{ ++ struct aspeed_jtag *aspeed_jtag = dev_id; ++ irqreturn_t ret; ++ u32 status; + -+#define IBI_QUEUE_STATUS 0x18 -+#define IBI_QUEUE_STATUS_DATA_LEN(x) ((x) & GENMASK(7, 0)) ++ status = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_ISR); + -+#define IBI_SIR_REQ_REJECT 0x30 -+#define INTR_STATUS_EN 0x40 -+#define INTR_SIGNAL_EN 0x44 -+#define INTR_IBI_THLD_STAT BIT(2) ++ if (status & ASPEED_JTAG_ISR_INT_MASK) { ++ aspeed_jtag_write(aspeed_jtag, ++ (status & ASPEED_JTAG_ISR_INT_MASK) | ++ (status & ++ ASPEED_JTAG_ISR_INT_EN_MASK), ++ ASPEED_JTAG_ISR); ++ aspeed_jtag->flag |= status & ASPEED_JTAG_ISR_INT_MASK; ++ } + -+#define QUEUE_STATUS_LEVEL 0x4c -+#define QUEUE_STATUS_IBI_STATUS_CNT(x) (((x) & GENMASK(28, 24)) >> 24) ++ if (aspeed_jtag->flag) { ++ wake_up_interruptible(&aspeed_jtag->jtag_wq); ++ ret = IRQ_HANDLED; ++ } else { ++ dev_err(aspeed_jtag->dev, "irq status:%x\n", status); ++ ret = IRQ_NONE; ++ } ++ return ret; ++} + -+#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) ++static irqreturn_t aspeed_jtag_interrupt_hw2(s32 this_irq, void *dev_id) ++{ ++ struct aspeed_jtag *aspeed_jtag = dev_id; ++ irqreturn_t ret; ++ u32 status; + -+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; ++ status = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_INTCTRL); + -+ struct ast2600_i3c_swdat_group dat_group[NUM_OF_SWDAT_GROUP]; - }; - -+static u8 even_parity(u8 p) -+{ -+ p ^= p >> 4; -+ p &= 0xf; ++ if (status & ASPEED_JTAG_INTCTRL_SHCPL_IRQ_STAT) { ++ aspeed_jtag_write(aspeed_jtag, ++ status | ASPEED_JTAG_INTCTRL_SHCPL_IRQ_STAT, ++ ASPEED_JTAG_INTCTRL); ++ aspeed_jtag->flag |= status & ASPEED_JTAG_INTCTRL_SHCPL_IRQ_STAT; ++ } + -+ return (0x9669 >> p) & 1; ++ if (aspeed_jtag->flag) { ++ wake_up_interruptible(&aspeed_jtag->jtag_wq); ++ ret = IRQ_HANDLED; ++ } else { ++ dev_err(aspeed_jtag->dev, "irq status:%x\n", status); ++ ret = IRQ_NONE; ++ } ++ return ret; +} + -+static inline struct dw_i3c_master * -+to_dw_i3c_master(struct i3c_master_controller *master) ++static int aspeed_jtag_enable(struct jtag *jtag) +{ -+ return container_of(master, struct dw_i3c_master, base); ++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); ++ ++ aspeed_jtag->llops->master_enable(aspeed_jtag); ++ return 0; +} + - 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) ++static int aspeed_jtag_disable(struct jtag *jtag) +{ -+ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); -+ -+ 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); ++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); + -+ 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); ++ aspeed_jtag->llops->output_disable(aspeed_jtag); ++ return 0; +} + -+static void ast2600_i3c_exit_sw_mode(struct dw_i3c_master *dw) ++static int aspeed_jtag_init(struct platform_device *pdev, ++ struct aspeed_jtag *aspeed_jtag) +{ -+ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); ++ struct resource *res; + -+ regmap_write_bits(i3c->global_regs, AST2600_I3CG_REG1(i3c->global_idx), -+ SCL_IN_SW_MODE_EN | SDA_IN_SW_MODE_EN, 0); -+} ++ memset(aspeed_jtag->pad_data_one, ~0, ++ sizeof(aspeed_jtag->pad_data_one)); ++ memset(aspeed_jtag->pad_data_zero, 0, ++ sizeof(aspeed_jtag->pad_data_zero)); + -+static void ast2600_i3c_toggle_scl_in(struct dw_i3c_master *dw, int count) -+{ -+ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ aspeed_jtag->reg_base = devm_ioremap_resource(aspeed_jtag->dev, res); ++ if (IS_ERR(aspeed_jtag->reg_base)) ++ return -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); ++ aspeed_jtag->pclk = devm_clk_get(aspeed_jtag->dev, NULL); ++ if (IS_ERR(aspeed_jtag->pclk)) { ++ dev_err(aspeed_jtag->dev, "devm_clk_get failed\n"); ++ return PTR_ERR(aspeed_jtag->pclk); + } -+} -+ -+static void ast2600_i3c_gen_internal_stop(struct dw_i3c_master *dw) -+{ -+ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); + -+ 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); -+} ++ aspeed_jtag->irq = platform_get_irq(pdev, 0); ++ if (aspeed_jtag->irq < 0) ++ dev_warn(aspeed_jtag->dev, ++ "no irq specified, using polling mode"); + -+static int aspeed_i3c_bus_recovery(struct dw_i3c_master *dw) -+{ -+ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); -+ int i, ret = -1; ++ if (clk_prepare_enable(aspeed_jtag->pclk)) { ++ dev_err(aspeed_jtag->dev, "no irq specified\n"); ++ return -ENOENT; ++ } + -+ 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); ++ aspeed_jtag->rst = devm_reset_control_get_shared(&pdev->dev, NULL); ++ if (IS_ERR(aspeed_jtag->rst)) { ++ dev_err(aspeed_jtag->dev, ++ "missing or invalid reset controller device tree entry"); ++ return PTR_ERR(aspeed_jtag->rst); ++ } ++ reset_control_deassert(aspeed_jtag->rst); + -+ 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 (aspeed_jtag->irq >= 0) { ++ aspeed_jtag->irq = ++ devm_request_irq(aspeed_jtag->dev, aspeed_jtag->irq, ++ aspeed_jtag->llops->jtag_interrupt, 0, ++ "aspeed-jtag", aspeed_jtag); ++ if (aspeed_jtag->irq) { ++ dev_warn(aspeed_jtag->dev, ++ "unable to request IRQ, using polling mode"); + } + } + -+ 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"); ++ aspeed_jtag->llops->output_disable(aspeed_jtag); + -+ return ret; ++ aspeed_jtag->flag = 0; ++ aspeed_jtag->mode = 0; ++ init_waitqueue_head(&aspeed_jtag->jtag_wq); ++ return 0; +} + -+static void ast2600_i3c_gen_target_reset_pattern(struct dw_i3c_master *dw) ++static int aspeed_jtag_deinit(struct platform_device *pdev, ++ struct aspeed_jtag *aspeed_jtag) +{ -+ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); -+ int i; ++ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_ISR); ++ /* Disable clock */ ++ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_CTRL); ++ reset_control_assert(aspeed_jtag->rst); ++ clk_disable_unprepare(aspeed_jtag->pclk); ++ return 0; ++} + -+ 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; -+ } -+ -+ 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); ++static int aspeed_jtag_trst_set_hw1(struct aspeed_jtag *aspeed_jtag, u32 active) ++{ ++ aspeed_jtag_write(aspeed_jtag, active ? 0 : ASPEED_JTAG_EC_TRSTn_HIGH, ++ ASPEED_JTAG_EC); ++ return 0; +} + -+static void aspeed_i3c_drain_ibi_queue(struct dw_i3c_master *dw) ++static int aspeed_jtag_trst_set_hw2(struct aspeed_jtag *aspeed_jtag, u32 active) +{ -+ /* -+ * 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; ++ u32 reg_val; + -+ for (i = 0; i < nwords; i++) -+ readl(dw->regs + IBI_QUEUE_STATUS); ++ reg_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_GBLCTRL); ++ if (active) ++ reg_val |= ASPEED_JTAG_GBLCTRL_TRST; ++ else ++ reg_val &= ~ASPEED_JTAG_GBLCTRL_TRST; ++ aspeed_jtag_write(aspeed_jtag, reg_val, ASPEED_JTAG_GBLCTRL); ++ return 0; +} + -+static bool ast2600_i3c_fsm_exit_serv_ibi(struct dw_i3c_master *dw) ++static int aspeed_jtag_trst_set(struct jtag *jtag, u32 active) +{ -+ 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. -+ */ -+ 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; ++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); + -+ return true; ++ return aspeed_jtag->llops->trst_set(aspeed_jtag, active); +} + -+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; ++static const struct jtag_ops aspeed_jtag_ops = { ++ .freq_get = aspeed_jtag_freq_get, ++ .freq_set = aspeed_jtag_freq_set, ++ .status_get = aspeed_jtag_status_get, ++ .status_set = aspeed_jtag_status_set, ++ .xfer = aspeed_jtag_xfer, ++ .mode_set = aspeed_jtag_mode_set, ++ .bitbang = aspeed_jtag_bitbang, ++ .enable = aspeed_jtag_enable, ++ .disable = aspeed_jtag_disable ++}; + -+ 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); ++static const struct jtag_ops aspeed_jtag_ops_26xx = { ++#ifdef ASPEED_JTAG_HW_MODE_2_ENABLE ++ .freq_get = aspeed_jtag_freq_get_26xx, ++ .freq_set = aspeed_jtag_freq_set_26xx, ++ .status_get = aspeed_jtag_status_get, ++ .status_set = aspeed_jtag_status_set_26xx, ++#else ++ .freq_get = aspeed_jtag_freq_get, ++ .freq_set = aspeed_jtag_freq_set, ++ .status_get = aspeed_jtag_status_get, ++ .status_set = aspeed_jtag_status_set, ++#endif ++ .xfer = aspeed_jtag_xfer, ++ .mode_set = aspeed_jtag_mode_set, ++ .trst_set = aspeed_jtag_trst_set, ++ .bitbang = aspeed_jtag_bitbang, ++ .enable = aspeed_jtag_enable, ++ .disable = aspeed_jtag_disable ++}; + -+ 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); -+ } -+} ++static const struct jtag_low_level_functions ast25xx_llops = { ++ .master_enable = aspeed_jtag_master, ++ .output_disable = aspeed_jtag_output_disable, ++ .xfer_push_data = aspeed_jtag_xfer_push_data, ++ .xfer_push_data_last = aspeed_jtag_xfer_push_data_last, ++ .xfer_sw = aspeed_jtag_xfer_sw, ++ .xfer_hw = aspeed_jtag_xfer_hw, ++ .xfer_hw_fifo_delay = NULL, ++ .xfer_sw_delay = NULL, ++ .jtag_interrupt = aspeed_jtag_interrupt, ++ .trst_set = aspeed_jtag_trst_set_hw1 ++}; + -+static void ast2600_i3c_set_ibi_mdb(struct dw_i3c_master *dw, u8 mdb) -+{ -+ u32 reg; ++static const struct aspeed_jtag_functions ast25xx_functions = { ++ .aspeed_jtag_ops = &aspeed_jtag_ops, ++ .aspeed_jtag_llops = &ast25xx_llops ++}; + -+ 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 const struct jtag_low_level_functions ast26xx_llops = { ++#ifdef ASPEED_JTAG_HW_MODE_2_ENABLE ++ .master_enable = aspeed_jtag_master_26xx, ++ .output_disable = aspeed_jtag_output_disable_26xx, ++ .xfer_push_data = aspeed_jtag_xfer_push_data_26xx, ++ .xfer_push_data_last = aspeed_jtag_xfer_push_data_last_26xx, ++ .xfer_sw = aspeed_jtag_xfer_sw, ++ .xfer_hw = aspeed_jtag_xfer_hw2, ++ .xfer_hw_fifo_delay = aspeed_jtag_xfer_hw_fifo_delay_26xx, ++ .xfer_sw_delay = aspeed_jtag_sw_delay_26xx, ++ .jtag_interrupt = aspeed_jtag_interrupt_hw2, ++ .trst_set = aspeed_jtag_trst_set_hw2 ++#else ++ .master_enable = aspeed_jtag_master, ++ .output_disable = aspeed_jtag_output_disable, ++ .xfer_push_data = aspeed_jtag_xfer_push_data_26xx, ++ .xfer_push_data_last = aspeed_jtag_xfer_push_data_last_26xx, ++ .xfer_sw = aspeed_jtag_xfer_sw, ++ .xfer_hw = aspeed_jtag_xfer_hw, ++ .xfer_hw_fifo_delay = aspeed_jtag_xfer_hw_fifo_delay_26xx, ++ .xfer_sw_delay = aspeed_jtag_sw_delay_26xx, ++ .jtag_interrupt = aspeed_jtag_interrupt, ++ .trst_set = aspeed_jtag_trst_set_hw1 ++#endif ++}; + -+static int ast2600_i3c_get_free_hw_pos(struct dw_i3c_master *dw) -+{ -+ if (!(dw->free_pos & GENMASK(dw->maxdevs - 1, 0))) -+ return -ENOSPC; ++static const struct aspeed_jtag_functions ast26xx_functions = { ++ .aspeed_jtag_ops = &aspeed_jtag_ops_26xx, ++ .aspeed_jtag_llops = &ast26xx_llops ++}; + -+ return ffs(dw->free_pos) - 1; -+} ++static const struct of_device_id aspeed_jtag_of_match[] = { ++ { .compatible = "aspeed,ast2400-jtag", .data = &ast25xx_functions }, ++ { .compatible = "aspeed,ast2500-jtag", .data = &ast25xx_functions }, ++ { .compatible = "aspeed,ast2600-jtag", .data = &ast26xx_functions }, ++ { .compatible = "aspeed,ast2700-jtag", .data = &ast26xx_functions }, ++ {} ++}; + -+static void ast2600_i3c_init_swdat(struct dw_i3c_master *dw) ++static int aspeed_jtag_probe(struct platform_device *pdev) +{ -+ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); -+ struct ast2600_i3c_swdat_group *gp; -+ int i, j; -+ u32 def_set, def_clr; -+ -+ def_clr = DEV_ADDR_TABLE_IBI_ADDR_MASK; -+ def_set = DEV_ADDR_TABLE_MR_REJECT | DEV_ADDR_TABLE_SIR_REJECT; ++ struct aspeed_jtag *aspeed_jtag; ++ struct jtag *jtag; ++ const struct of_device_id *match; ++ const struct aspeed_jtag_functions *jtag_functions; ++ int err; + -+ 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; ++ match = of_match_node(aspeed_jtag_of_match, pdev->dev.of_node); ++ if (!match) ++ return -ENODEV; ++ jtag_functions = match->data; + -+ for (j = 0; j < NUM_OF_SWDATS_IN_GROUP; j++) -+ gp->dat[j] = 0; -+ } ++ jtag = jtag_alloc(&pdev->dev, sizeof(*aspeed_jtag), ++ jtag_functions->aspeed_jtag_ops); ++ if (!jtag) ++ return -ENOMEM; + -+ for (i = 0; i < dw->maxdevs; i++) -+ writel(def_set, -+ dw->regs + DEV_ADDR_TABLE_LOC(dw->datstartaddr, i)); -+} ++ platform_set_drvdata(pdev, jtag); ++ aspeed_jtag = jtag_priv(jtag); ++ aspeed_jtag->dev = &pdev->dev; + -+static int ast2600_i3c_set_swdat(struct dw_i3c_master *dw, u8 addr, u32 val) -+{ -+ 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); ++ aspeed_jtag->llops = jtag_functions->aspeed_jtag_llops; + -+ 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; ++ /* Initialize device*/ ++ err = aspeed_jtag_init(pdev, aspeed_jtag); ++ if (err) ++ goto err_jtag_init; + -+ if (val) { -+ gp->free_pos &= ~BIT(pos); ++ /* Initialize JTAG core structure*/ ++ err = devm_jtag_register(aspeed_jtag->dev, jtag); ++ if (err) ++ goto err_jtag_register; + -+ /* -+ * 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; ++ jtag_functions->aspeed_jtag_ops->freq_set(jtag, 1000000); + -+ 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); ++ return 0; + -+ /* -+ * 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; ++err_jtag_register: ++ aspeed_jtag_deinit(pdev, aspeed_jtag); ++err_jtag_init: ++ jtag_free(jtag); ++ return err; +} + -+static u32 ast2600_i3c_get_swdat(struct dw_i3c_master *dw, u8 addr) ++static void aspeed_jtag_remove(struct platform_device *pdev) +{ -+ struct ast2600_i3c *i3c = to_ast2600_i3c(dw); -+ struct ast2600_i3c_swdat_group *gp = &i3c->dat_group[ADDR_GRP(addr)]; ++ struct jtag *jtag = platform_get_drvdata(pdev); + -+ return gp->dat[ADDR_HID(addr)]; ++ aspeed_jtag_deinit(pdev, jtag_priv(jtag)); +} + -+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; ++static struct platform_driver aspeed_jtag_driver = { ++ .probe = aspeed_jtag_probe, ++ .remove = aspeed_jtag_remove, ++ .driver = { ++ .name = ASPEED_JTAG_NAME, ++ .of_match_table = aspeed_jtag_of_match, ++ }, ++}; ++module_platform_driver(aspeed_jtag_driver); + -+ if (!dat || hw_index < 0) -+ return -1; ++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 + -+ dat &= ~gp->mask.clr; -+ dat |= gp->mask.set; -+ writel(dat, dw->regs + DEV_ADDR_TABLE_LOC(dw->datstartaddr, hw_index)); ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ return 0; -+} ++static char *end_status_str[] = { "tlr", "idle", "selDR", "capDR", "sDR", ++ "ex1DR", "pDR", "ex2DR", "updDR", "selIR", ++ "capIR", "sIR", "ex1IR", "pIR", "ex2IR", ++ "updIR", "current" }; + -+static int ast2600_i3c_get_swdat_hw_pos(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)]; ++struct jtag { ++ struct miscdevice miscdev; ++ const struct jtag_ops *ops; ++ int id; ++ unsigned long *priv; ++}; + -+ return gp->hw_index; ++static DEFINE_IDA(jtag_ida); ++ ++void *jtag_priv(struct jtag *jtag) ++{ ++ return jtag->priv; +} ++EXPORT_SYMBOL_GPL(jtag_priv); + -+static int ast2600_i3c_reattach_i3c_dev(struct i3c_dev_desc *dev, -+ u8 old_dyn_addr) ++static long jtag_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ -+ 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 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 (old_dyn_addr != dev->info.dyn_addr) -+ ast2600_i3c_set_swdat(master, old_dyn_addr, 0); ++ if (!arg) ++ return -EINVAL; + -+ 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; ++ switch (cmd) { ++ case JTAG_GIOCFREQ: ++ if (!jtag->ops->freq_get) ++ return -EOPNOTSUPP; + -+ return 0; -+} ++ err = jtag->ops->freq_get(jtag, &value); ++ if (err) ++ break; ++ dev_dbg(jtag->miscdev.parent, "JTAG_GIOCFREQ: freq get = %d", ++ value); + -+static int ast2600_i3c_attach_i3c_dev(struct i3c_dev_desc *dev) -+{ -+ 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; ++ if (put_user(value, (__u32 __user *)arg)) ++ err = -EFAULT; ++ break; + -+ pos = ast2600_i3c_set_swdat(master, addr, -+ FIELD_PREP(DEV_ADDR_TABLE_DYNAMIC_ADDR, addr)); -+ if (pos < 0) -+ return pos; ++ case JTAG_SIOCFREQ: ++ if (!jtag->ops->freq_set) ++ return -EOPNOTSUPP; + -+ data = kzalloc(sizeof(*data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; ++ if (get_user(value, (__u32 __user *)arg)) ++ return -EFAULT; ++ if (value == 0) ++ return -EINVAL; + -+ data->index = ast2600_i3c_get_swdat_hw_pos(master, addr); -+ master->devs[addr].addr = addr; -+ i3c_dev_set_master_data(dev, data); ++ err = jtag->ops->freq_set(jtag, value); ++ dev_dbg(jtag->miscdev.parent, "JTAG_SIOCFREQ: freq set = %d", ++ value); ++ break; + -+ if (master->base.bus.context == I3C_BUS_CONTEXT_JESD403) { -+ dev->info.max_write_ds = 0; -+ dev->info.max_read_ds = 0; -+ } ++ case JTAG_SIOCSTATE: ++ if (copy_from_user(&tapstate, (const void __user *)arg, ++ sizeof(struct jtag_tap_state))) ++ return -EFAULT; + -+ return 0; -+} ++ if (tapstate.from > JTAG_STATE_CURRENT) ++ return -EINVAL; + -+static void ast2600_i3c_detach_i3c_dev(struct i3c_dev_desc *dev) -+{ -+ 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; ++ if (tapstate.endstate > JTAG_STATE_CURRENT) ++ return -EINVAL; + -+ ast2600_i3c_set_swdat(master, addr, 0); ++ if (tapstate.reset > JTAG_FORCE_RESET) ++ return -EINVAL; + -+ i3c_dev_set_master_data(dev, NULL); -+ master->devs[addr].addr = 0; -+ kfree(data); -+} ++ 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); + -+static int ast2600_i3c_attach_i2c_dev(struct i2c_dev_desc *dev) -+{ -+ 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; ++ err = jtag->ops->status_set(jtag, &tapstate); ++ break; + -+ 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; ++ case JTAG_IOCXFER: ++ { ++ u8 ubit_mask = GENMASK(7, 0); ++ u8 remaining_bits = 0x0; ++ union pad_config padding; + -+ data = kzalloc(sizeof(*data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; ++ if (copy_from_user(&xfer, (const void __user *)arg, ++ sizeof(struct jtag_xfer))) ++ return -EFAULT; + -+ 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); ++ if (xfer.length >= JTAG_MAX_XFER_DATA_LEN) ++ return -EINVAL; + -+ return 0; -+} ++ if (xfer.type > JTAG_SDR_XFER) ++ return -EINVAL; + -+static void ast2600_i3c_detach_i2c_dev(struct i2c_dev_desc *dev) -+{ -+ 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); ++ if (xfer.direction > JTAG_READ_WRITE_XFER) ++ return -EINVAL; + -+ ast2600_i3c_set_swdat(master, dev->addr, 0); ++ if (xfer.from > JTAG_STATE_CURRENT) ++ return -EINVAL; + -+ i2c_dev_set_master_data(dev, NULL); -+ master->devs[dev->addr].addr = 0; -+ kfree(data); -+} ++ if (xfer.endstate > JTAG_STATE_CURRENT) ++ return -EINVAL; + -+static void ast2600_i3c_set_sir_enabled(struct dw_i3c_master *dw, -+ struct i3c_dev_desc *dev, u8 idx, -+ bool enable) -+{ -+ 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; ++ data_size = DIV_ROUND_UP(xfer.length, BITS_PER_BYTE); ++ xfer_data = memdup_user(u64_to_user_ptr(xfer.tdio), data_size); + -+ spin_lock_irqsave(&dw->devs_lock, flags); -+ if (enable) { -+ gp->mask.clr |= DEV_ADDR_TABLE_SIR_REJECT | -+ DEV_ADDR_TABLE_IBI_ADDR_MASK; ++ /* 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; ++ } + -+ 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); -+ } ++ 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); + -+ 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; ++ print_hex_dump_debug("I:", DUMP_PREFIX_NONE, 16, 1, xfer_data, ++ data_size, false); + -+ for (i = 0; i < NUM_OF_SWDATS_IN_GROUP; i++) { -+ if (!(gp->dat[i] & DEV_ADDR_TABLE_SIR_REJECT)) { -+ ibi_enable = true; -+ break; -+ } ++ err = jtag->ops->xfer(jtag, &xfer, xfer_data); ++ if (err) { ++ kfree(xfer_data); ++ return err; + } + -+ if (!ibi_enable) { -+ reg |= BIT(gp->hw_index); -+ global = (reg == 0xffffffff) && hj_rejected; ++ print_hex_dump_debug("O:", DUMP_PREFIX_NONE, 16, 1, xfer_data, ++ data_size, false); + -+ gp->mask.set = DEV_ADDR_TABLE_SIR_REJECT; -+ } -+ } -+ writel(reg, dw->regs + IBI_SIR_REQ_REJECT); ++ /* Restore unused remaining bits in this transfer */ ++ xfer_data[data_size - 1] = (xfer_data[data_size - 1] ++ & ubit_mask) | remaining_bits; + -+ 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); ++ err = copy_to_user(u64_to_user_ptr(xfer.tdio), ++ (void *)xfer_data, data_size); ++ kfree(xfer_data); ++ if (err) ++ return -EFAULT; + -+ 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 (copy_to_user((void __user *)arg, (void *)&xfer, ++ sizeof(struct jtag_xfer))) ++ return -EFAULT; ++ break; + } + -+ ast2600_i3c_flush_swdat(dw, dev->info.dyn_addr); ++ 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]); + -+ spin_unlock_irqrestore(&dw->devs_lock, flags); -+} ++ 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; + -+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 (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 void ast2600_i3c_unset_ibi_dev(struct dw_i3c_master *dw, -+ struct i3c_dev_desc *dev) ++static int jtag_open(struct inode *inode, struct file *file) +{ -+ dw->devs[dev->info.dyn_addr].ibi_dev = NULL; ++ 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 struct i3c_dev_desc *ast2600_i3c_get_ibi_dev(struct dw_i3c_master *dw, -+ u8 addr) ++static int jtag_release(struct inode *inode, struct file *file) +{ -+ return dw->devs[addr].ibi_dev; ++ struct jtag *jtag = file->private_data; ++ ++ if (jtag->ops->disable(jtag)) ++ return -EBUSY; ++ return 0; +} + - 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; ++static const struct file_operations jtag_fops = { ++ .owner = THIS_MODULE, ++ .open = jtag_open, ++ .llseek = noop_llseek, ++ .unlocked_ioctl = jtag_ioctl, ++ .release = jtag_release, ++}; + -+ ast2600_i3c_init_swdat(&i3c->dw); ++struct jtag *jtag_alloc(struct device *host, size_t priv_size, ++ const struct jtag_ops *ops) ++{ ++ struct jtag *jtag; + - 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-04-08 18:03:48.261706215 +0000 -@@ -0,0 +1,413 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+#ifndef VENDOR_ASPEED_H -+#define VENDOR_ASPEED_H ++ if (!host) ++ return NULL; + -+/* 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 (!ops) ++ return NULL; + -+#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 ++ if (!ops->status_set || !ops->status_get || !ops->xfer) ++ return NULL; + -+#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) ++ jtag = kzalloc(sizeof(*jtag), GFP_KERNEL); ++ if (!jtag) ++ return NULL; ++ jtag->priv = kzalloc(priv_size, GFP_KERNEL); ++ if (!jtag->priv) ++ return NULL; + -+#define ASPEED_I3C_DAA_INDEX0 0x10 -+#define ASPEED_I3C_DAA_INDEX1 0x14 -+#define ASPEED_I3C_DAA_INDEX2 0x18 -+#define ASPEED_I3C_DAA_INDEX3 0x1C ++ jtag->ops = ops; ++ jtag->miscdev.parent = host; + -+#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 ++ return jtag; ++} ++EXPORT_SYMBOL_GPL(jtag_alloc); + -+#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 ++void jtag_free(struct jtag *jtag) ++{ ++ kfree(jtag); ++} ++EXPORT_SYMBOL_GPL(jtag_free); + -+#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) ++static int jtag_register(struct jtag *jtag) ++{ ++ struct device *dev = jtag->miscdev.parent; ++ int err; ++ int id; + -+#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 (!dev) ++ return -ENODEV; + -+#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) ++ id = ida_simple_get(&jtag_ida, 0, 0, GFP_KERNEL); ++ if (id < 0) ++ return id; + -+#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) ++ jtag->id = id; + -+#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) ++ 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; ++ } + -+#define ASPEED_I3C_INTR_RENEW 0xF4 ++ err = misc_register(&jtag->miscdev); ++ if (err) { ++ dev_err(jtag->miscdev.parent, "Unable to register device\n"); ++ goto err_jtag_name; ++ } ++ return 0; + -+/* 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)) ++err_jtag_name: ++ kfree(jtag->miscdev.name); ++err_jtag_alloc: ++ ida_simple_remove(&jtag_ida, id); ++ return err; ++} + -+#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 void jtag_unregister(struct jtag *jtag) ++{ ++ misc_deregister(&jtag->miscdev); ++ kfree(jtag->miscdev.name); ++ ida_simple_remove(&jtag_ida, jtag->id); ++} + -+/* 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) ++static void devm_jtag_unregister(struct device *dev, void *res) ++{ ++ jtag_unregister(*(struct jtag **)res); ++} + -+#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 ++int devm_jtag_register(struct device *dev, struct jtag *jtag) ++{ ++ struct jtag **ptr; ++ int ret; + -+/* 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) ++ ptr = devres_alloc(devm_jtag_unregister, sizeof(struct jtag *), ++ GFP_KERNEL); ++ if (!ptr) ++ return -ENOMEM; + -+#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 ++ ret = jtag_register(jtag); ++ if (!ret) { ++ *ptr = jtag; ++ devres_add(dev, ptr); ++ } else { ++ devres_free(ptr); ++ } ++ return ret; ++} ++EXPORT_SYMBOL_GPL(devm_jtag_register); + -+/* 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 void __exit jtag_exit(void) ++{ ++ ida_destroy(&jtag_ida); ++} + -+#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 ++module_exit(jtag_exit); + -+/* 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) ++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. + -+/* 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 + 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 + -+#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) ++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 +@@ -0,0 +1,235 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright Aspeed Technology Inc. (C) 2025. All rights reserved ++ */ + -+/* 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+#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 ++/* Each bit in the register represents an IPC ID */ ++#define IPCR_TX_TRIG 0x00 ++#define IPCR_ENABLE 0x04 ++#define IPCR_STATUS 0x08 ++#define RX_IRQ(n) BIT(n) ++#define RX_IRQ_MASK 0xf ++#define IPCR_DATA 0x10 + -+#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) ++struct ast2700_mbox_data { ++ u8 num_chans; ++ u8 msg_size; ++}; + -+#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 ++struct ast2700_mbox { ++ struct mbox_controller mbox; ++ u8 msg_size; ++ void __iomem *tx_regs; ++ void __iomem *rx_regs; ++ spinlock_t lock; /* control register lock */ ++}; + -+static inline unsigned int aspeed_get_avail_tx_entries(struct i3c_hci *hci) ++static inline int ch_num(struct mbox_chan *chan) +{ -+ unsigned int queue_ptr, entries; -+ -+ 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); -+ -+ return entries; ++ return chan - chan->mbox->chans; +} + -+static inline unsigned int aspeed_get_received_rx_entries(struct i3c_hci *hci) ++static inline bool ast2700_mbox_tx_done(struct ast2700_mbox *mb, int idx) +{ -+ unsigned int queue_ptr, entries; -+ -+ 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 entries; ++ return !(readl(mb->tx_regs + IPCR_STATUS) & BIT(idx)); +} + -+static inline unsigned int aspeed_get_i3c_revision_id(struct i3c_hci *hci) ++static irqreturn_t ast2700_mbox_irq(int irq, void *p) +{ -+ return FIELD_GET(GENMASK(23, 16), hci->vendor_product_id); -+} ++ struct ast2700_mbox *mb = p; ++ void __iomem *data_reg; ++ int num_words = mb->msg_size / sizeof(u32); ++ u32 *word_data; ++ u32 status; ++ int n, i; + -+static inline void aspeed_i3c_ccc_handler(struct i3c_hci *hci, u8 ccc) -+{ -+ u32 reg; -+ u8 dynamic_addr; ++ /* Only examine channels that are currently enabled. */ ++ status = readl(mb->rx_regs + IPCR_ENABLE) & ++ readl(mb->rx_regs + IPCR_STATUS); + -+ 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; -+ } -+} ++ if (!(status & RX_IRQ_MASK)) ++ return IRQ_NONE; + -+#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 2026-04-08 18:03:46.423739796 +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. ++ for (n = 0; n < mb->mbox.num_chans; ++n) { ++ struct mbox_chan *chan = &mb->mbox.chans[n]; + -+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. ++ if (!(status & RX_IRQ(n))) ++ continue; + -+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-04-08 18:03:46.423739796 +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-04-08 18:03:46.423739796 +0000 -@@ -0,0 +1,697 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* Copyright (C) 2022 Intel Corporation.*/ ++ data_reg = mb->rx_regs + IPCR_DATA + mb->msg_size * n; ++ word_data = chan->con_priv; ++ /* Read the message data */ ++ for (i = 0; i < num_words; i++) ++ word_data[i] = readl(data_reg + i * sizeof(u32)); + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++ mbox_chan_received_data(chan, chan->con_priv); + -+#include -+#include ++ /* The IRQ can be cleared only once the FIFO is empty. */ ++ writel(RX_IRQ(n), mb->rx_regs + IPCR_STATUS); ++ } + -+#include ++ return IRQ_HANDLED; ++} + -+#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 ast2700_mbox_send_data(struct mbox_chan *chan, void *data) ++{ ++ struct ast2700_mbox *mb = dev_get_drvdata(chan->mbox->dev); ++ int idx = ch_num(chan); ++ void __iomem *data_reg = mb->tx_regs + IPCR_DATA + mb->msg_size * idx; ++ u32 *word_data = data; ++ int num_words = mb->msg_size / sizeof(u32); ++ int i; + -+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; -+}; ++ if (!(readl(mb->tx_regs + IPCR_ENABLE) & BIT(idx))) { ++ dev_warn(mb->mbox.dev, "%s: Ch-%d not enabled yet\n", __func__, idx); ++ return -ENODEV; ++ } + -+struct i3c_mctp_client { -+ struct i3c_mctp *priv; -+ struct ptr_ring rx_queue; -+ wait_queue_head_t wait_queue; -+}; ++ if (!(ast2700_mbox_tx_done(mb, idx))) { ++ dev_warn(mb->mbox.dev, "%s: Ch-%d last data has not finished\n", __func__, idx); ++ return -EBUSY; ++ } + -+static struct class *i3c_mctp_class; -+static dev_t i3c_mctp_devt; -+static DEFINE_IDA(i3c_mctp_ida); ++ /* Write the message data */ ++ for (i = 0 ; i < num_words; i++) ++ writel(word_data[i], data_reg + i * sizeof(u32)); + -+static struct kmem_cache *packet_cache; ++ writel(BIT(idx), mb->tx_regs + IPCR_TX_TRIG); ++ dev_dbg(mb->mbox.dev, "%s: Ch-%d sent\n", __func__, idx); + -+/** -+ * 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); ++ return 0; +} -+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) ++static int ast2700_mbox_startup(struct mbox_chan *chan) +{ -+ kmem_cache_free(packet_cache, packet); -+} -+EXPORT_SYMBOL_GPL(i3c_mctp_packet_free); ++ struct ast2700_mbox *mb = dev_get_drvdata(chan->mbox->dev); ++ int idx = ch_num(chan); ++ void __iomem *reg = mb->rx_regs + IPCR_ENABLE; ++ unsigned long flags; + -+static void i3c_mctp_client_free(struct i3c_mctp_client *client) -+{ -+ ptr_ring_cleanup(&client->rx_queue, &i3c_mctp_packet_free); ++ spin_lock_irqsave(&mb->lock, flags); ++ writel(readl(reg) | BIT(idx), reg); ++ spin_unlock_irqrestore(&mb->lock, flags); + -+ kfree(client); ++ return 0; +} + -+static struct i3c_mctp_client *i3c_mctp_client_alloc(struct i3c_mctp *priv) ++static void ast2700_mbox_shutdown(struct mbox_chan *chan) +{ -+ struct i3c_mctp_client *client; -+ int ret; -+ -+ client = kzalloc(sizeof(*client), GFP_KERNEL); -+ if (!client) -+ goto out; ++ struct ast2700_mbox *mb = dev_get_drvdata(chan->mbox->dev); ++ int idx = ch_num(chan); ++ void __iomem *reg = mb->rx_regs + IPCR_ENABLE; ++ unsigned long flags; + -+ 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; ++ spin_lock_irqsave(&mb->lock, flags); ++ writel(readl(reg) & ~BIT(idx), reg); ++ spin_unlock_irqrestore(&mb->lock, flags); +} + -+static struct i3c_mctp_client *i3c_mctp_find_client(struct i3c_mctp *priv, -+ struct i3c_mctp_packet *packet) ++static bool ast2700_mbox_last_tx_done(struct mbox_chan *chan) +{ -+ 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; ++ struct ast2700_mbox *mb = dev_get_drvdata(chan->mbox->dev); ++ int idx = ch_num(chan); + -+ return priv->default_client; ++ return ast2700_mbox_tx_done(mb, idx); +} + -+static struct i3c_mctp_packet *i3c_mctp_read_packet(struct i3c_device *i3c) ++static const struct mbox_chan_ops ast2700_mbox_chan_ops = { ++ .send_data = ast2700_mbox_send_data, ++ .startup = ast2700_mbox_startup, ++ .shutdown = ast2700_mbox_shutdown, ++ .last_tx_done = ast2700_mbox_last_tx_done, ++}; ++ ++static int ast2700_mbox_probe(struct platform_device *pdev) +{ -+ 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; ++ struct ast2700_mbox *mb; ++ const struct ast2700_mbox_data *dev_data; ++ struct device *dev = &pdev->dev; ++ int irq, ret; + -+ rx_packet = i3c_mctp_packet_alloc(GFP_KERNEL); -+ if (!rx_packet) -+ return ERR_PTR(-ENOMEM); ++ if (!pdev->dev.of_node) ++ return -ENODEV; + -+ rx_packet->size = I3C_MCTP_PACKET_SIZE; -+ xfers.len = rx_packet->size; -+ xfers.data.in = &rx_packet->data; ++ dev_data = device_get_match_data(&pdev->dev); + -+ /* 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); ++ mb = devm_kzalloc(dev, sizeof(*mb), GFP_KERNEL); ++ if (!mb) ++ return -ENOMEM; ++ ++ mb->mbox.chans = devm_kcalloc(&pdev->dev, dev_data->num_chans, ++ sizeof(*mb->mbox.chans), GFP_KERNEL); ++ if (!mb->mbox.chans) ++ return -ENOMEM; ++ ++ /* con_priv of each channel is used to store the message received */ ++ for (int i = 0; i < dev_data->num_chans; i++) { ++ mb->mbox.chans[i].con_priv = devm_kcalloc(dev, dev_data->msg_size, ++ sizeof(u8), GFP_KERNEL); ++ if (!mb->mbox.chans[i].con_priv) ++ return -ENOMEM; + } -+ 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); -+ } ++ platform_set_drvdata(pdev, mb); + -+ return rx_packet; -+} ++ mb->tx_regs = devm_platform_ioremap_resource_byname(pdev, "tx"); ++ if (IS_ERR(mb->tx_regs)) ++ return PTR_ERR(mb->tx_regs); + -+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; ++ mb->rx_regs = devm_platform_ioremap_resource_byname(pdev, "rx"); ++ if (IS_ERR(mb->rx_regs)) ++ return PTR_ERR(mb->rx_regs); + -+ ret = ptr_ring_produce(&client->rx_queue, packet); -+ if (ret) -+ i3c_mctp_packet_free(packet); -+ else -+ wake_up_all(&client->wait_queue); -+} ++ mb->msg_size = dev_data->msg_size; ++ mb->mbox.dev = dev; ++ mb->mbox.num_chans = dev_data->num_chans; ++ mb->mbox.ops = &ast2700_mbox_chan_ops; ++ mb->mbox.txdone_irq = false; ++ mb->mbox.txdone_poll = true; ++ mb->mbox.txpoll_period = 5; ++ spin_lock_init(&mb->lock); + -+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; ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) ++ return irq; + -+ i3c_device_get_info(i3cdev, &info); -+ ret = i3c_device_getstatus_ccc(i3cdev, &info); ++ ret = devm_request_irq(dev, irq, ast2700_mbox_irq, 0, dev_name(dev), mb); + 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; ++ return ret; + -+ ret = i3c_device_do_priv_xfers(i3c, &xfers, 1); -+ } -+ kfree(data); -+ return ret ?: count; ++ return devm_mbox_controller_register(dev, &mb->mbox); +} + -+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; ++static const struct ast2700_mbox_data ast2700_dev_data = { ++ .num_chans = 4, ++ .msg_size = 0x20, ++}; + -+ i3c_mctp_packet_free(rx_packet); ++static const struct of_device_id ast2700_mbox_of_match[] = { ++ { .compatible = "aspeed,ast2700-mailbox", .data = &ast2700_dev_data }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, ast2700_mbox_of_match); + -+ return count; -+} ++static struct platform_driver ast2700_mbox_driver = { ++ .driver = { ++ .name = "ast2700-mailbox", ++ .of_match_table = ast2700_mbox_of_match, ++ }, ++ .probe = ast2700_mbox_probe, ++}; ++module_platform_driver(ast2700_mbox_driver); + -+static int i3c_mctp_open(struct inode *inode, struct file *file) -+{ -+ struct i3c_mctp *priv = container_of(inode->i_cdev, struct i3c_mctp, cdev); ++MODULE_AUTHOR("Jammy Huang "); ++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 +@@ -4,6 +4,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -25,6 +26,9 @@ + #include + #include + #include ++#include ++#include ++#include + #include + #include + #include +@@ -96,6 +100,7 @@ + #define VE_CTRL_INTERLACE BIT(14) + #define VE_CTRL_HSYNC_POL_CTRL BIT(15) + #define VE_CTRL_FRC GENMASK(23, 16) ++#define AST2600_VE_CTRL_EN_COMPARE_ONLY BIT(31) + + #define VE_TGS_0 0x00c + #define VE_TGS_1 0x010 +@@ -149,6 +154,8 @@ + #define AST2400_VE_COMP_SIZE_READ_BACK 0x078 + #define AST2600_VE_COMP_SIZE_READ_BACK 0x084 + ++#define VE_COMP_FRAME_COUNT_READ_BACK 0x07C + -+ 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); + #define VE_SRC_LR_EDGE_DET 0x090 + #define VE_SRC_LR_EDGE_DET_LEFT GENMASK(11, 0) + #define VE_SRC_LR_EDGE_DET_NO_V BIT(12) +@@ -203,6 +210,51 @@ + #define VE_MEM_RESTRICT_START 0x310 + #define VE_MEM_RESTRICT_END 0x314 + ++/* SCU's registers */ ++#define SCU_MISC_CTRL 0xC0 ++#define SCU_DPLL_SOURCE BIT(20) + -+ file->private_data = priv; ++#define SCU_CLK_SEL 0x288 ++#define SCU_SOC_DISPLAY_SEL BIT(15) + -+ return 0; -+} ++#define SCU_CLK_SEL2 0x304 ++#define SCU_VIDEO_OUTPUT_DELAY GENMASK(5, 0) + -+static int i3c_mctp_release(struct inode *inode, struct file *file) -+{ -+ struct i3c_mctp *priv = file->private_data; ++#define SCU_CRT2CLK 0x350 ++#define SCU_CRT2CLK_N GENMASK(31, 16) ++#define SCU_CRT2CLK_R GENMASK(15, 0) + -+ spin_lock(&priv->device_file_lock); -+ priv->device_open--; -+ spin_unlock(&priv->device_file_lock); ++#define SCU_MULTI_FUNC_12 0x440 ++#define SCU_MULTI_FUNC_CPU_SLI_DIR BIT(5) ++#define SCU_MULTI_FUNC_15 0x454 ++#define SCU_MULTI_FUNC_IO_SLI_DIR BIT(21) + -+ file->private_data = NULL; ++/* GFX's registers */ ++#define GFX_CTRL 0x60 ++#define GFX_CTRL_ENABLE BIT(0) ++#define GFX_CTRL_FMT GENMASK(9, 7) + -+ return 0; -+} ++#define GFX_H_DISPLAY 0x70 ++#define GFX_H_DISPLAY_DE GENMASK(28, 16) ++#define GFX_H_DISPLAY_TOTAL GENMASK(12, 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; ++#define GFX_V_DISPLAY 0x78 ++#define GFX_V_DISPLAY_DE GENMASK(27, 16) ++#define GFX_V_DISPLAY_TOTAL GENMASK(11, 0) + -+ poll_wait(file, &priv->default_client->wait_queue, pt); ++#define GFX_DISPLAY_ADDR 0x80 + -+ if (__ptr_ring_peek(&priv->default_client->rx_queue)) -+ ret |= EPOLLIN; ++enum { ++ VIDEO_CLK_25MHz = 0, ++ VIDEO_CLK_D1, ++ VIDEO_CLK_D2, ++ VIDEO_CLK_CRT1, ++ VIDEO_CLK_CRT2, ++ VIDEO_CLK_HPLL, ++ VIDEO_CLK_MPLL, ++ VIDEO_CLK_48MHz, ++}; + -+ return ret; -+} + /* + * VIDEO_MODE_DETECT_DONE: a flag raised if signal lock + * VIDEO_RES_CHANGE: a flag raised if res_change work on-going +@@ -211,6 +263,7 @@ + * VIDEO_FRAME_INPRG: a flag raised if hw working on a frame + * VIDEO_STOPPED: a flag raised if device release + * VIDEO_CLOCKS_ON: a flag raised if clk is on ++ * VIDEO_BOUNDING_BOX: a flag raised if box-finding for partial-jpeg + */ + enum { + VIDEO_MODE_DETECT_DONE, +@@ -220,12 +273,14 @@ + VIDEO_FRAME_INPRG, + VIDEO_STOPPED, + VIDEO_CLOCKS_ON, ++ VIDEO_BOUNDING_BOX, + }; + + enum aspeed_video_format { + VIDEO_FMT_STANDARD = 0, + VIDEO_FMT_ASPEED, +- VIDEO_FMT_MAX = VIDEO_FMT_ASPEED ++ VIDEO_FMT_PARTIAL, ++ VIDEO_FMT_MAX = VIDEO_FMT_PARTIAL + }; + + // for VE_CTRL_CAPTURE_FMT +@@ -243,6 +298,11 @@ + void *virt; + }; + ++struct aspeed_video_box { ++ struct v4l2_rect box; ++ struct list_head link; ++}; + -+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, + struct aspeed_video_buffer { + struct vb2_v4l2_buffer vb; + struct list_head link; +@@ -262,6 +322,9 @@ + /* + * struct aspeed_video - driver data + * ++ * version: holds the version of aspeed SoC ++ * base: holds the base address of video engine ++ * dvi_base: holds the base address of DVI engine. For 2700 dvi support. + * res_work: holds the delayed_work for res-detection if unlock + * buffers: holds the list of buffer queued from user + * flags: holds the state of video +@@ -270,9 +333,11 @@ + * srcs: holds the buffer information for srcs + * jpeg: holds the buffer information for jpeg header + * bcd: holds the buffer information for bcd work ++ * dbg_src: holds the buffer information for debug input + * yuv420: a flag raised if JPEG subsampling is 420 + * format: holds the video format + * hq_mode: a flag raised if HQ is enabled. Only for VIDEO_FMT_ASPEED ++ * input: holds the video input + * frame_rate: holds the frame_rate + * jpeg_quality: holds jpeq's quality (0~11) + * jpeg_hq_quality: holds hq's quality (1~12) only if hq_mode enabled +@@ -281,11 +346,16 @@ + * frame_right: end position of video data in horizontal direction + * frame_top: start position of video data in vertical direction + * perf: holds the statistics primary for debugfs ++ * bounding_box: holds the video rect for partial-jpeg ++ * boxes: holds the list of video-rect info for each partial-jpeg + */ + struct aspeed_video { + void __iomem *base; ++ void __iomem *dvi_base; + struct clk *eclk; + struct clk *vclk; ++ struct clk *crt2clk; ++ struct reset_control *reset; + + struct device *dev; + struct v4l2_ctrl_handler ctrl_handler; +@@ -297,9 +367,15 @@ + struct vb2_queue queue; + struct video_device vdev; + struct mutex video_lock; /* v4l2 and videobuf2 lock */ ++ struct dentry *debugfs_entry; ++ int id; + ++ struct regmap *scu; ++ struct regmap *gfx; ++ u32 version; + u32 jpeg_mode; + u32 comp_size_read; ++ u32 compare_only; + + wait_queue_head_t wait; + spinlock_t lock; /* buffer list lock */ +@@ -307,15 +383,20 @@ + struct list_head buffers; + unsigned long flags; + unsigned int sequence; ++ struct workqueue_struct *rst_wq; ++ struct work_struct rst_work; + + unsigned int max_compressed_size; ++ struct aspeed_video_addr pool; + struct aspeed_video_addr srcs[2]; + struct aspeed_video_addr jpeg; + struct aspeed_video_addr bcd; ++ struct aspeed_video_addr dbg_src; + + bool yuv420; + enum aspeed_video_format format; + bool hq_mode; ++ enum aspeed_video_input input; + unsigned int frame_rate; + unsigned int jpeg_quality; + unsigned int jpeg_hq_quality; +@@ -326,28 +407,45 @@ + unsigned int frame_top; + + struct aspeed_video_perf perf; ++ struct v4l2_rect bounding_box; ++ struct list_head boxes; + }; + + #define to_aspeed_video(x) container_of((x), struct aspeed_video, v4l2_dev) + + struct aspeed_video_config { ++ u32 version; + u32 jpeg_mode; + u32 comp_size_read; ++ u32 compare_only; + }; + + static const struct aspeed_video_config ast2400_config = { ++ .version = 4, + .jpeg_mode = AST2400_VE_SEQ_CTRL_JPEG_MODE, + .comp_size_read = AST2400_VE_COMP_SIZE_READ_BACK, ++ .compare_only = 0, + }; + + static const struct aspeed_video_config ast2500_config = { ++ .version = 5, + .jpeg_mode = AST2500_VE_SEQ_CTRL_JPEG_MODE, + .comp_size_read = AST2400_VE_COMP_SIZE_READ_BACK, ++ .compare_only = 0, + }; + + 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, ++ .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, ++ .compare_only = AST2600_VE_CTRL_EN_COMPARE_ONLY, + }; + + static const u32 aspeed_video_jpeg_header[ASPEED_VIDEO_JPEG_HEADER_SIZE] = { +@@ -484,9 +582,12 @@ + }; + + static const char * const format_str[] = {"Standard JPEG", +- "Aspeed JPEG"}; ++ "Aspeed JPEG", "Partial JPEG"}; ++static const char * const input_str[] = {"HOST VGA", "BMC GFX", "MEMORY", "DVI"}; + + static unsigned int debug; ++static unsigned int dual_flag; ++DECLARE_WAIT_QUEUE_HEAD(waitq); + + static bool aspeed_video_alloc_buf(struct aspeed_video *video, + struct aspeed_video_addr *addr, +@@ -495,6 +596,22 @@ + static void aspeed_video_free_buf(struct aspeed_video *video, + struct aspeed_video_addr *addr); + +/** -+ * i3c_mctp_add_peci_client() - registers PECI client -+ * @i3c: I3C device to get the PECI client for ++ * _make_addr - make address fit for ast2700 ++ * @addr: dma address for hardware to work + * -+ * Return: pointer to PECI client, -ENOMEM - in case of client alloc fault ++ * Return: 32bit format of address + */ -+struct i3c_mctp_client *i3c_mctp_add_peci_client(struct i3c_device *i3c) ++static inline u32 _make_addr(dma_addr_t addr) +{ -+ 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; ++#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT ++ // In ast2700, it store higt byte[35:32] in low byte[3:0] ++ return (addr >> 32) | (u32)(addr); ++#else ++ return addr; ++#endif +} -+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 void aspeed_video_init_jpeg_table(u32 *table, bool yuv420) + { + int i; +@@ -576,13 +693,58 @@ + p->duration); + } + ++static void aspeed_video_partial_jpeg_update_regs(struct aspeed_video *v) +{ -+ struct i3c_mctp *priv = client->priv; -+ -+ i3c_mctp_client_free(priv->peci_client); ++ if (test_bit(VIDEO_BOUNDING_BOX, &v->flags)) { ++ aspeed_video_update(v, VE_SEQ_CTRL, ++ v->jpeg_mode, ++ VE_SEQ_CTRL_AUTO_COMP); ++ aspeed_video_update(v, VE_BCD_CTRL, 0, ++ VE_BCD_CTRL_EN_BCD); ++ aspeed_video_write(v, VE_COMP_WINDOW, ++ v->pix_fmt.width << 16 | ++ v->pix_fmt.height); ++ v4l2_dbg(1, debug, &v->v4l2_dev, ++ "%s: BCD enabled\n", __func__); ++ } else { ++ u32 scan_lines = aspeed_video_read(v, VE_SRC_SCANLINE_OFFSET); ++ u32 frame_count = aspeed_video_read(v, VE_COMP_FRAME_COUNT_READ_BACK); ++ u32 old_src_addr, new_src_addr; ++ dma_addr_t addr; ++ u32 offset; + -+ priv->peci_client = NULL; -+} -+EXPORT_SYMBOL_GPL(i3c_mctp_remove_peci_client); ++ if (v->version >= 7) { ++ old_src_addr = (frame_count & 0x01) ? VE_SRC0_ADDR : VE_SRC1_ADDR; ++ new_src_addr = (frame_count & 0x01) ? VE_SRC1_ADDR : VE_SRC0_ADDR; ++ } else { ++ old_src_addr = VE_SRC0_ADDR; ++ new_src_addr = VE_SRC0_ADDR; ++ } ++ addr = aspeed_video_read(v, old_src_addr); + -+static struct i3c_mctp *i3c_mctp_alloc(struct i3c_device *i3c) -+{ -+ struct i3c_mctp *priv; -+ int id; ++ aspeed_video_update(v, VE_SEQ_CTRL, ++ VE_SEQ_CTRL_AUTO_COMP, ++ v->jpeg_mode); ++ aspeed_video_update(v, VE_BCD_CTRL, ++ VE_BCD_CTRL_EN_BCD, 0); ++ aspeed_video_write(v, VE_COMP_WINDOW, ++ v->bounding_box.width << 16 | ++ v->bounding_box.height); + -+ priv = devm_kzalloc(i3cdev_to_dev(i3c), sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return ERR_PTR(-ENOMEM); ++ offset = (scan_lines * v->bounding_box.top) + ++ ((256 * v->bounding_box.left) >> (v->yuv420 ? 4 : 3)); ++ aspeed_video_write(v, new_src_addr, addr + offset); ++ v4l2_dbg(1, debug, &v->v4l2_dev, ++ "%s: BCD disabled, frame#(%d) offset(0x%x)\n", __func__, frame_count, offset); ++ } ++} + -+ id = ida_alloc(&i3c_mctp_ida, GFP_KERNEL); -+ if (id < 0) { -+ pr_err("i3c_mctp: no minor number available!\n"); -+ return ERR_PTR(id); + static int aspeed_video_start_frame(struct aspeed_video *video) + { + dma_addr_t addr; + unsigned long flags; + struct aspeed_video_buffer *buf; + u32 seq_ctrl = aspeed_video_read(video, VE_SEQ_CTRL); +- bool bcd_buf_need = (video->format != VIDEO_FMT_STANDARD); + + if (video->v4l2_input_status) { + v4l2_dbg(1, debug, &video->v4l2_dev, "No signal; don't start frame\n"); +@@ -595,18 +757,14 @@ + return -EBUSY; + } + +- if (bcd_buf_need && !video->bcd.size) { +- if (!aspeed_video_alloc_buf(video, &video->bcd, +- VE_BCD_BUFF_SIZE)) { +- dev_err(video->dev, "Failed to allocate BCD buffer\n"); +- dev_err(video->dev, "don't start frame\n"); +- return -ENOMEM; +- } +- aspeed_video_write(video, VE_BCD_ADDR, video->bcd.dma); +- v4l2_dbg(1, debug, &video->v4l2_dev, "bcd addr(%pad) size(%d)\n", +- &video->bcd.dma, video->bcd.size); +- } else if (!bcd_buf_need && video->bcd.size) { +- aspeed_video_free_buf(video, &video->bcd); ++ if (video->input == VIDEO_INPUT_GFX) { ++ u32 val; ++ ++ // update input buffer address as gfx's ++ regmap_read(video->gfx, GFX_DISPLAY_ADDR, &val); ++ aspeed_video_write(video, VE_TGS_0, val); ++ } else if (video->input == VIDEO_INPUT_MEM) { ++ aspeed_video_write(video, VE_TGS_0, _make_addr(video->dbg_src.dma)); + } + + spin_lock_irqsave(&video->lock, flags); +@@ -624,15 +782,26 @@ + + aspeed_video_write(video, VE_COMP_PROC_OFFSET, 0); + aspeed_video_write(video, VE_COMP_OFFSET, 0); +- aspeed_video_write(video, VE_COMP_ADDR, addr); ++ aspeed_video_write(video, VE_COMP_ADDR, _make_addr(addr)); + + aspeed_video_update(video, VE_INTERRUPT_CTRL, 0, + VE_INTERRUPT_COMP_COMPLETE); + +- video->perf.last_sample = ktime_get(); +- +- aspeed_video_update(video, VE_SEQ_CTRL, 0, +- VE_SEQ_CTRL_TRIG_CAPTURE | VE_SEQ_CTRL_TRIG_COMP); ++ if (video->format == VIDEO_FMT_PARTIAL) { ++ aspeed_video_partial_jpeg_update_regs(video); ++ if (test_bit(VIDEO_BOUNDING_BOX, &video->flags)) { ++ video->perf.last_sample = ktime_get(); ++ seq_ctrl = VE_SEQ_CTRL_TRIG_CAPTURE | VE_SEQ_CTRL_TRIG_COMP; ++ aspeed_video_update(video, VE_CTRL, video->compare_only, video->compare_only); ++ } else { ++ seq_ctrl = VE_SEQ_CTRL_TRIG_COMP; ++ aspeed_video_update(video, VE_CTRL, video->compare_only, 0); ++ } ++ } else { ++ video->perf.last_sample = ktime_get(); ++ seq_ctrl = VE_SEQ_CTRL_TRIG_CAPTURE | VE_SEQ_CTRL_TRIG_COMP; + } ++ aspeed_video_update(video, VE_SEQ_CTRL, 0, seq_ctrl); + + return 0; + } +@@ -660,6 +829,9 @@ + aspeed_video_write(video, VE_INTERRUPT_CTRL, 0); + aspeed_video_write(video, VE_INTERRUPT_STATUS, 0xffffffff); + ++ reset_control_assert(video->reset); ++ usleep_range(100, 200); + -+ priv->id = id; -+ priv->i3c = i3c; + /* Turn off the relevant clocks */ + clk_disable(video->eclk); + clk_disable(video->vclk); +@@ -676,7 +848,68 @@ + clk_enable(video->vclk); + clk_enable(video->eclk); + ++ mdelay(10); ++ reset_control_deassert(video->reset); + -+ spin_lock_init(&priv->device_file_lock); + set_bit(VIDEO_CLOCKS_ON, &video->flags); + -+ return priv; ++ if (video->version >= 7) ++ queue_work(video->rst_wq, &video->rst_work); +} + -+static void i3c_mctp_ibi_handler(struct i3c_device *dev, const struct i3c_ibi_payload *payload) ++static void aspeed_video_reset(struct aspeed_video *v) +{ -+ struct i3c_mctp *priv = dev_get_drvdata(i3cdev_to_dev(dev)); -+ struct i3c_mctp_packet *rx_packet; ++ int rc; ++ u32 val; + -+ rx_packet = i3c_mctp_read_packet(dev); -+ if (IS_ERR(rx_packet)) -+ return; ++ reset_control_assert(v->reset); ++ rc = reset_control_status(v->reset); ++ if (rc == 0) { ++ /* 2700 has 2 VE, but only 1 reset. To have reset work, we need ++ * to notify the other VE if reset is not asserted. ++ */ ++ val = 1 << (v->id ^ 1); ++ dual_flag |= val; ++ v4l2_dbg(2, debug, &v->v4l2_dev, "%s: reset not asserted, needs another VE(%x)\n", __func__, val); ++ wake_up_all(&waitq); ++ rc = wait_event_interruptible(waitq, (dual_flag & val) != val); ++ if (rc) ++ v4l2_dbg(2, debug, &v->v4l2_dev, "%s: another VE done, dual_flag(%d)\n", __func__, dual_flag); ++ } + -+ i3c_mctp_dispatch_packet(priv, rx_packet); ++ usleep_range(100, 200); ++ reset_control_deassert(v->reset); ++ udelay(1); +} + -+static int i3c_mctp_init(struct i3c_driver *drv) ++/* ++ * aspeed_video_rst_worker: This is a work to wait event from the other VE to ++ * do full function reset because 2700's 2 VE share 1 reset line. When there ++ * is one VE wants reset, both VE needs to do it. ++ * ++ */ ++static void aspeed_video_rst_worker(struct work_struct *work) +{ -+ int ret; ++ struct aspeed_video *v = ++ container_of(work, struct aspeed_video, rst_work); ++ int rc; + -+ 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; ++ rc = wait_event_timeout(waitq, ++ (dual_flag & (1 << v->id)), ++ INVALID_RESOLUTION_DELAY); ++ if (rc) { ++ v4l2_dbg(2, debug, &v->v4l2_dev, "%s: dual_flag(%x)\n", __func__, dual_flag); ++ dual_flag = 0; ++ set_bit(VIDEO_RES_CHANGE, &v->flags); ++ clear_bit(VIDEO_FRAME_INPRG, &v->flags); ++ schedule_delayed_work(&v->res_work, 0); ++ wait_event_interruptible(v->wait, ++ !test_bit(VIDEO_RES_CHANGE, &v->flags)); ++ v4l2_dbg(2, debug, &v->v4l2_dev, "%s: rst and clear, %d\n", __func__, rc); + } + -+ /* Dynamically request unused major number */ -+ ret = alloc_chrdev_region(&i3c_mctp_devt, 0, I3C_MCTP_MINORS, "i3c-mctp"); -+ if (ret) -+ goto out; ++ if (test_bit(VIDEO_CLOCKS_ON, &v->flags)) ++ queue_work(v->rst_wq, &v->rst_work); + } + + static void aspeed_video_bufs_done(struct aspeed_video *video, +@@ -684,11 +917,18 @@ + { + unsigned long flags; + struct aspeed_video_buffer *buf; ++ struct aspeed_video_box *box, *tmp; + + spin_lock_irqsave(&video->lock, flags); + list_for_each_entry(buf, &video->buffers, link) + vb2_buffer_done(&buf->vb.vb2_buf, state); + INIT_LIST_HEAD(&video->buffers); + -+ /* 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; ++ list_for_each_entry_safe(box, tmp, &video->boxes, link) { ++ list_del(&box->link); ++ kfree(box); + } ++ INIT_LIST_HEAD(&video->boxes); + spin_unlock_irqrestore(&video->lock, flags); + } + +@@ -701,12 +941,96 @@ + + video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; + +- aspeed_video_off(video); ++ aspeed_video_write(video, VE_INTERRUPT_CTRL, 0); ++ aspeed_video_write(video, VE_INTERRUPT_STATUS, 0xffffffff); + aspeed_video_bufs_done(video, VB2_BUF_STATE_ERROR); + + schedule_delayed_work(&video->res_work, delay); + } + ++static inline bool _box_data_changed(struct aspeed_video *v, u8 data) ++{ ++ if (v->version >= 6) ++ return ((data & 0xf) != 0xf); + -+ 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; ++ return ((data & 0xf) == 0xf); +} + -+static void i3c_mctp_free(struct i3c_driver *drv) ++static void aspeed_video_get_bounding_box(struct aspeed_video *v, ++ struct v4l2_rect *box) +{ -+ i3c_driver_unregister(drv); -+ class_destroy(i3c_mctp_class); -+ unregister_chrdev_region(i3c_mctp_devt, I3C_MCTP_MINORS); -+ kmem_cache_destroy(packet_cache); -+} ++ u16 min_x, min_y, max_x, max_y; ++ u16 w, h, i, j; ++ u32 bytesperline; ++ u8 mb_shift = v->yuv420 ? 4 : 3; ++ u8 *bcd_buf = v->bcd.virt; + -+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; ++ if (!bcd_buf) { ++ box->left = 0; ++ box->top = 0; ++ box->width = v->pix_fmt.width; ++ box->height = v->pix_fmt.width; ++ v4l2_dbg(1, debug, &v->v4l2_dev, "%s: bcd buf not ready yet\n", __func__); ++ return; ++ } + -+ ret = i3c_device_request_ibi(i3cdev, &ibireq); -+ if (ret) -+ return ret; -+ ret = i3c_device_enable_ibi(i3cdev); -+ if (ret) -+ i3c_device_free_ibi(i3cdev); ++ w = v->pix_fmt.width >> mb_shift; ++ h = v->pix_fmt.height >> mb_shift; ++ v4l2_dbg(1, debug, &v->v4l2_dev, "%s: macrobox_shift(%d) size (%d * %d)\n", ++ __func__, mb_shift, w, h); + -+ return ret; -+} ++ min_x = 0x3ff; ++ min_y = 0x3ff; ++ max_x = 0; ++ max_y = 0; + -+static void i3c_mctp_disable_ibi(struct i3c_device *i3cdev) -+{ -+ i3c_device_disable_ibi(i3cdev); -+ i3c_device_free_ibi(i3cdev); -+} ++ for (j = 0; j < h; j++) { ++ bytesperline = w * j; ++ for (i = 0; i < w; i++) { ++ if (_box_data_changed(v, *(bcd_buf + bytesperline + i))) { ++ min_x = min(i, min_x); ++ max_x = max(i, max_x); ++ min_y = min(j, min_y); ++ max_y = max(j, max_y); + -+/** -+ * 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); ++ // skip line if max_x can't be bigger ++ if (max_x == w) ++ i = w; ++ // skip the pixels between min_x ~ max_x ++ if (max_x > min_x && i > min_x && i < max_x) ++ i = max_x; ++ } ++ } ++ } ++ v4l2_dbg(1, debug, &v->v4l2_dev, ++ "%s: left %d right %d top %d bottom %d\n", __func__, ++ min_x, max_x, min_y, max_y); + -+/** -+ * 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; ++ // clear bcd flag ++ if (v->version < 6) ++ memset(bcd_buf, 0x01, (w * h)); + -+ 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); ++ // use full size every 8 frames ++ if (IS_ALIGNED(v->sequence, 8)) { ++ min_x = 0; ++ max_x = w - 1; ++ min_y = 0; ++ max_y = h - 1; ++ } else if (min_x > max_x || min_y > max_y || max_x > w || max_y > h) { ++ memset(box, 0, sizeof(*box)); ++ v4l2_dbg(1, debug, &v->v4l2_dev, "box not found\n"); ++ return; + } -+ 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); ++ box->left = min_x << mb_shift; ++ box->top = min_y << mb_shift; ++ box->width = (max_x + 1 - min_x) << mb_shift; ++ box->height = (max_y + 1 - min_y) << mb_shift; ++ v4l2_dbg(1, debug, &v->v4l2_dev, ++ "%s: x: %d, y: %d, w: %d , h: %d\n", __func__, ++ box->left, box->top, box->width, box->height); +} -+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); + static void aspeed_video_swap_src_buf(struct aspeed_video *v) + { + if (v->format == VIDEO_FMT_STANDARD) +@@ -716,24 +1040,100 @@ + if (IS_ALIGNED(v->sequence, 8)) + memset((u8 *)v->bcd.virt, 0x00, VE_BCD_BUFF_SIZE); + ++ // 2700's new design will automatically swap src at each operation ++ if (v->version > 6 && v->format == VIDEO_FMT_ASPEED) ++ return; + -+ rx_packet = ptr_ring_consume(&client->rx_queue); -+ if (!rx_packet) -+ return ERR_PTR(-EAGAIN); + if (v->sequence & 0x01) { +- aspeed_video_write(v, VE_SRC0_ADDR, v->srcs[1].dma); +- aspeed_video_write(v, VE_SRC1_ADDR, v->srcs[0].dma); ++ aspeed_video_write(v, VE_SRC0_ADDR, _make_addr(v->srcs[1].dma)); ++ aspeed_video_write(v, VE_SRC1_ADDR, _make_addr(v->srcs[0].dma)); + } else { +- aspeed_video_write(v, VE_SRC0_ADDR, v->srcs[0].dma); +- 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) ++{ ++ struct aspeed_video_buffer *buf; ++ bool empty = true; ++ u32 frame_size; + -+ return rx_packet; -+} -+EXPORT_SYMBOL_GPL(i3c_mctp_receive_packet); ++ if (!buf_done) ++ return; + -+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)); ++ spin_lock(&video->lock); ++ clear_bit(VIDEO_FRAME_INPRG, &video->flags); ++ buf = list_first_entry_or_null(&video->buffers, ++ struct aspeed_video_buffer, ++ link); ++ if (buf) { ++ frame_size = aspeed_video_read(video, ++ video->comp_size_read); ++ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, frame_size); + -+ switch (event) { -+ case i3c_event_prepare_for_rescan: + /* -+ * Disable IBI and polling mode blindly. ++ * VIDEO_FMT_ASPEED requires continuous update. ++ * On the contrary, standard jpeg can keep last buffer ++ * to always have the latest result. + */ -+ 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 (video->format != VIDEO_FMT_ASPEED && ++ list_is_last(&buf->link, &video->buffers)) { ++ empty = false; ++ v4l2_dbg(1, debug, &video->v4l2_dev, "skip to keep last frame updated\n"); ++ } else { ++ buf->vb.vb2_buf.timestamp = ktime_get_ns(); ++ buf->vb.sequence = video->sequence++; ++ buf->vb.field = V4L2_FIELD_NONE; ++ vb2_buffer_done(&buf->vb.vb2_buf, ++ VB2_BUF_STATE_DONE); ++ list_del(&buf->link); ++ empty = list_empty(&video->buffers); ++ if (video->format == VIDEO_FMT_PARTIAL) { ++ struct aspeed_video_box *box = ++ kmalloc(sizeof(struct aspeed_video_box), ++ GFP_KERNEL); ++ ++ box->box = video->bounding_box; ++ list_add_tail(&box->link, &video->boxes); ++ } + } -+ break; -+ default: -+ break; ++ } ++ spin_unlock(&video->lock); ++ ++ aspeed_video_swap_src_buf(video); ++ ++ if (test_bit(VIDEO_STREAMING, &video->flags) && !empty && ++ video->input != VIDEO_INPUT_MEM) { ++ set_bit(VIDEO_BOUNDING_BOX, &video->flags); ++ aspeed_video_start_frame(video); + } +} + -+static int i3c_mctp_probe(struct i3c_device *i3cdev) ++static irqreturn_t aspeed_video_thread_irq(int irq, void *arg) +{ -+ 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); ++ struct aspeed_video *v = arg; + -+ cdev_init(&priv->cdev, &i3c_mctp_fops); ++ aspeed_video_get_bounding_box(v, &v->bounding_box); + -+ priv->cdev.owner = THIS_MODULE; -+ ret = cdev_add(&priv->cdev, MKDEV(MAJOR(i3c_mctp_devt), priv->id), 1); -+ if (ret) -+ goto error_cdev; ++ if (v->bounding_box.width && v->bounding_box.height) ++ clear_bit(VIDEO_BOUNDING_BOX, &v->flags); ++ else ++ set_bit(VIDEO_BOUNDING_BOX, &v->flags); + -+ /* 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; -+ } ++ aspeed_video_start_frame(v); + -+ ret = i3c_device_control_pec(i3cdev, true); -+ if (ret) -+ dev_warn(priv->dev, "Hardware not support pec"); ++ return IRQ_HANDLED; ++} + -+ 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; + static irqreturn_t aspeed_video_irq(int irq, void *arg) + { + struct aspeed_video *video = arg; + u32 sts = aspeed_video_read(video, VE_INTERRUPT_STATUS); ++ bool get_box = false; + +- /* +- * Hardware sometimes asserts interrupts that we haven't actually +- * enabled; ignore them if so. +- */ ++ aspeed_video_write(video, VE_INTERRUPT_STATUS, sts); + 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 @@ + if (test_bit(VIDEO_RES_DETECT, &video->flags)) { + aspeed_video_update(video, VE_INTERRUPT_CTRL, + VE_INTERRUPT_MODE_DETECT, 0); +- aspeed_video_write(video, VE_INTERRUPT_STATUS, +- VE_INTERRUPT_MODE_DETECT); + sts &= ~VE_INTERRUPT_MODE_DETECT; + set_bit(VIDEO_MODE_DETECT_DONE, &video->flags); + wake_up_interruptible_all(&video->wait); +@@ -772,41 +1170,13 @@ + } + + if (sts & VE_INTERRUPT_COMP_COMPLETE) { +- struct aspeed_video_buffer *buf; +- bool empty = true; +- u32 frame_size = aspeed_video_read(video, +- video->comp_size_read); +- +- update_perf(&video->perf); +- +- spin_lock(&video->lock); +- clear_bit(VIDEO_FRAME_INPRG, &video->flags); +- buf = list_first_entry_or_null(&video->buffers, +- struct aspeed_video_buffer, +- link); +- if (buf) { +- vb2_set_plane_payload(&buf->vb.vb2_buf, 0, frame_size); ++ bool frame_done = false; + +- /* +- * aspeed_jpeg requires continuous update. +- * On the contrary, standard jpeg can keep last buffer +- * to always have the latest result. +- */ +- if (video->format == VIDEO_FMT_STANDARD && +- list_is_last(&buf->link, &video->buffers)) { +- empty = false; +- v4l2_dbg(1, debug, &video->v4l2_dev, "skip to keep last frame updated\n"); +- } else { +- buf->vb.vb2_buf.timestamp = ktime_get_ns(); +- buf->vb.sequence = video->sequence++; +- buf->vb.field = V4L2_FIELD_NONE; +- vb2_buffer_done(&buf->vb.vb2_buf, +- VB2_BUF_STATE_DONE); +- list_del(&buf->link); +- empty = list_empty(&video->buffers); +- } +- } +- spin_unlock(&video->lock); ++ if (video->format != VIDEO_FMT_PARTIAL) ++ frame_done = true; ++ else if (!test_bit(VIDEO_BOUNDING_BOX, &video->flags) && ++ video->bounding_box.width && video->bounding_box.height) ++ frame_done = true; + + aspeed_video_update(video, VE_SEQ_CTRL, + VE_SEQ_CTRL_TRIG_CAPTURE | +@@ -814,17 +1184,60 @@ + VE_SEQ_CTRL_TRIG_COMP, 0); + aspeed_video_update(video, VE_INTERRUPT_CTRL, + VE_INTERRUPT_COMP_COMPLETE, 0); +- aspeed_video_write(video, VE_INTERRUPT_STATUS, +- VE_INTERRUPT_COMP_COMPLETE); + sts &= ~VE_INTERRUPT_COMP_COMPLETE; + +- aspeed_video_swap_src_buf(video); ++ if (frame_done) { ++ update_perf(&video->perf); ++ aspeed_video_frame_done_handler(video, frame_done); ++ } else { ++ get_box = true; ++ } + } -+ 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; + +- if (test_bit(VIDEO_STREAMING, &video->flags) && !empty) +- aspeed_video_start_frame(video); ++ return get_box ? IRQ_WAKE_THREAD : IRQ_HANDLED; +} + -+static void i3c_mctp_remove(struct i3c_device *i3cdev) ++static irqreturn_t aspeed_video_md_irq(int irq, void *arg) +{ -+ 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-04-08 18:03:46.423739796 +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; -+ -+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; -+}; ++ struct aspeed_video *video = arg; ++ u32 sts; + -+static void *i3c_target_mctp_packet_alloc(u16 count) -+{ -+ struct mctp_packet *packet; -+ u8 *data; ++ sts = readl(video->dvi_base + VE_INTERRUPT_STATUS); ++ writel(sts, video->dvi_base + VE_INTERRUPT_STATUS); ++ sts &= readl(video->dvi_base + VE_INTERRUPT_CTRL); + -+ packet = kzalloc(sizeof(*packet), GFP_ATOMIC); -+ if (!packet) -+ return NULL; ++ v4l2_dbg(2, debug, &video->v4l2_dev, "dvi irq sts=%#x %s%s\n", sts, ++ sts & VE_INTERRUPT_MODE_DETECT_WD ? ", unlock" : "", ++ sts & VE_INTERRUPT_MODE_DETECT ? ", lock" : ""); + -+ data = kzalloc(count, GFP_ATOMIC); -+ if (!data) { -+ kfree(packet); -+ return NULL; ++ if (sts & VE_INTERRUPT_MODE_DETECT_WD) { ++ writel(0, video->dvi_base + VE_INTERRUPT_CTRL); ++ writel(0xffffffff, video->dvi_base + VE_INTERRUPT_STATUS); ++ aspeed_video_irq_res_change(video, 0); ++ return IRQ_HANDLED; + } + +- return sts ? IRQ_NONE : IRQ_HANDLED; ++ if (sts & VE_INTERRUPT_MODE_DETECT) { ++ if (test_bit(VIDEO_RES_DETECT, &video->flags)) { ++ aspeed_video_update(video, VE_INTERRUPT_CTRL, ++ VE_INTERRUPT_MODE_DETECT, 0); ++ sts &= ~VE_INTERRUPT_MODE_DETECT; ++ set_bit(VIDEO_MODE_DETECT_DONE, &video->flags); ++ wake_up_interruptible_all(&video->wait); ++ } else { ++ /* ++ * Signal acquired while NOT doing resolution ++ * detection; reset the engine and re-initialize ++ */ ++ writel(0, video->dvi_base + VE_INTERRUPT_CTRL); ++ writel(0xffffffff, video->dvi_base + VE_INTERRUPT_STATUS); ++ aspeed_video_irq_res_change(video, ++ RESOLUTION_CHANGE_DELAY); ++ return IRQ_HANDLED; ++ } + } + -+ 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) ++ return IRQ_HANDLED; + } + + static void aspeed_video_check_and_set_polarity(struct aspeed_video *video) +@@ -896,7 +1309,7 @@ + + /* + * Get the minimum HW-supported compression buffer size for the frame size. +- * Assume worst-case JPEG compression size is 1/8 raw size. This should be ++ * Assume worst-case JPEG compression size is 1/4 raw size. This should be + * plenty even for maximum quality; any worse and the engine will simply return + * incomplete JPEGs. + */ +@@ -908,7 +1321,7 @@ + unsigned int size; + const unsigned int num_compression_packets = 4; + const unsigned int compression_packet_size = 1024; +- const unsigned int max_compressed_size = frame_size / 2; /* 4bpp / 8 */ ++ const unsigned int max_compressed_size = frame_size; /* 4bpp / 4 */ + + video->max_compressed_size = UINT_MAX; + +@@ -929,6 +1342,7 @@ + aspeed_video_write(video, VE_STREAM_BUF_SIZE, + compression_buffer_size_reg); + ++ video->max_compressed_size = round_up(max_compressed_size, 0x10000); + v4l2_dbg(1, debug, &video->v4l2_dev, "Max compressed size: %#x\n", + video->max_compressed_size); + } +@@ -1026,9 +1440,23 @@ + } + } + ++static void aspeed_video_get_resolution_gfx(struct aspeed_video *video, ++ struct v4l2_bt_timings *det) +{ -+ struct mctp_client *client; ++ u32 h_val, v_val; + -+ client = kzalloc(sizeof(*client), GFP_KERNEL); -+ if (!client) -+ goto out; ++ regmap_read(video->gfx, GFX_H_DISPLAY, &h_val); ++ regmap_read(video->gfx, GFX_V_DISPLAY, &v_val); + -+ kref_init(&client->ref); -+ client->priv = priv; -+ ptr_ring_init(&client->rx_queue, RX_RING_COUNT, GFP_KERNEL); -+out: -+ return client; ++ det->width = FIELD_GET(GFX_H_DISPLAY_DE, h_val) + 1; ++ det->height = FIELD_GET(GFX_V_DISPLAY_DE, v_val) + 1; ++ video->v4l2_input_status = 0; +} + -+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); + #define res_check(v) test_and_clear_bit(VIDEO_MODE_DETECT_DONE, &(v)->flags) + +-static void aspeed_video_get_resolution(struct aspeed_video *video) ++static void aspeed_video_get_resolution_vga(struct aspeed_video *video, ++ struct v4l2_bt_timings *det) + { + bool invalid_resolution = true; + int rc; +@@ -1036,7 +1464,6 @@ + u32 mds; + u32 src_lr_edge; + u32 src_tb_edge; +- struct v4l2_bt_timings *det = &video->detected_timings; + + det->width = MIN_WIDTH; + det->height = MIN_HEIGHT; +@@ -1107,20 +1534,51 @@ + return; + } + ++ if (video->input == VIDEO_INPUT_DVI && video->version == 6) ++ video->frame_right -= 1; + -+ kfree(client); + det->height = (video->frame_bottom - video->frame_top) + 1; + det->width = (video->frame_right - video->frame_left) + 1; + video->v4l2_input_status = 0; + + aspeed_video_get_timings(video, det); + +- /* +- * Enable mode-detect watchdog, resolution-change watchdog and +- * automatic compression after frame capture. +- */ ++ /* Enable mode-detect watchdog, resolution-change watchdog */ + aspeed_video_update(video, VE_INTERRUPT_CTRL, 0, + VE_INTERRUPT_MODE_DETECT_WD); +- aspeed_video_update(video, VE_SEQ_CTRL, 0, +- VE_SEQ_CTRL_AUTO_COMP | VE_SEQ_CTRL_EN_WATCHDOG); ++ aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_EN_WATCHDOG); +} + -+static void i3c_target_mctp_client_get(struct mctp_client *client) ++/* ++ * For ast2700 only. Due to hw design, the timing detection of DVI is ++ * in io-die. Thus, we need to use another hw to do this job. ++ */ ++static void aspeed_video_get_resolution_dvi(struct aspeed_video *video, ++ struct v4l2_bt_timings *det) +{ -+ kref_get(&client->ref); -+} ++ void *base = video->base; + -+static void i3c_target_mctp_client_put(struct mctp_client *client) -+{ -+ kref_put(&client->ref, &i3c_target_mctp_client_free); ++ video->base = video->dvi_base; ++ aspeed_video_get_resolution_vga(video, det); ++ video->base = base; +} + -+static void -+i3c_target_mctp_rx_packet_enqueue(struct i3c_device *i3cdev, const u8 *data, size_t count) ++static void aspeed_video_get_resolution(struct aspeed_video *video) +{ -+ 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); ++ struct v4l2_bt_timings *det = &video->detected_timings; + -+ if (!client) ++ // if input is MEM, leave resolution decided by user through set_dv_timings ++ if (video->input == VIDEO_INPUT_MEM) { ++ video->v4l2_input_status = 0; + 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); ++ if (video->input == VIDEO_INPUT_GFX) ++ aspeed_video_get_resolution_gfx(video, det); ++ else if (video->input == VIDEO_INPUT_DVI && video->version == 7) ++ aspeed_video_get_resolution_dvi(video, det); + else -+ wake_up_all(&client->wait_queue); -+err: -+ i3c_target_mctp_client_put(client); -+} ++ aspeed_video_get_resolution_vga(video, det); + + v4l2_dbg(1, debug, &video->v4l2_dev, "Got resolution: %dx%d\n", + det->width, det->height); +@@ -1130,6 +1588,7 @@ + { + 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); + + /* Set capture/compression frame sizes */ + aspeed_video_calc_compressed_size(video, size); +@@ -1156,7 +1615,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) */ +- if (size < DIRECT_FETCH_THRESHOLD) { ++ if (video->input == VIDEO_INPUT_VGA && size < DIRECT_FETCH_THRESHOLD && ++ is_sync_mode_ok) { + 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 @@ + aspeed_video_update(video, VE_CTRL, + VE_CTRL_INT_DE | VE_CTRL_DIRECT_FETCH, + VE_CTRL_INT_DE); ++ } else if (video->input == VIDEO_INPUT_DVI) { ++ v4l2_dbg(1, debug, &video->v4l2_dev, "Capture: Sync Mode for external source\n"); ++ aspeed_video_update(video, VE_CTRL, ++ VE_CTRL_INT_DE | VE_CTRL_DIRECT_FETCH, ++ 0); + } else { ++ u32 ctrl, val, bpp; + -+static struct mctp_client *i3c_target_mctp_create_client(struct i3c_target_mctp *priv) + v4l2_dbg(1, debug, &video->v4l2_dev, "Capture: Direct Mode\n"); ++ ctrl = VE_CTRL_DIRECT_FETCH; ++ if (video->input == VIDEO_INPUT_GFX) { ++ regmap_read(video->gfx, GFX_CTRL, &val); ++ bpp = FIELD_GET(GFX_CTRL_FMT, val) ? 32 : 16; ++ if (bpp == 16) ++ ctrl |= VE_CTRL_INT_DE; ++ aspeed_video_write(video, VE_TGS_1, act->width * (bpp >> 3)); ++ } else { ++ // stride should be the same with capture window width ++ val = aspeed_video_read(video, VE_CAP_WINDOW) >> 16; ++ aspeed_video_write(video, VE_TGS_1, val * 4); ++ } + aspeed_video_update(video, VE_CTRL, + VE_CTRL_INT_DE | VE_CTRL_DIRECT_FETCH, +- VE_CTRL_DIRECT_FETCH); +- } +- +- size *= 4; +- +- if (size != video->srcs[0].size) { +- if (video->srcs[0].size) +- aspeed_video_free_buf(video, &video->srcs[0]); +- if (video->srcs[1].size) +- aspeed_video_free_buf(video, &video->srcs[1]); +- +- if (!aspeed_video_alloc_buf(video, &video->srcs[0], size)) +- goto err_mem; +- if (!aspeed_video_alloc_buf(video, &video->srcs[1], size)) +- goto err_mem; +- +- v4l2_dbg(1, debug, &video->v4l2_dev, "src buf0 addr(%pad) size(%d)\n", +- &video->srcs[0].dma, video->srcs[0].size); +- v4l2_dbg(1, debug, &video->v4l2_dev, "src buf1 addr(%pad) size(%d)\n", +- &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)); ++} + +-err_mem: +- dev_err(video->dev, "Failed to allocate source buffers\n"); ++/* ++ * Update relative parameters when timing changed. ++ * ++ * @video: the struct of aspeed_video ++ * @timings: the new timings ++ */ ++static void aspeed_video_update_timings(struct aspeed_video *video, struct v4l2_bt_timings *timings) +{ -+ 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); -+} ++ video->active_timings = *timings; ++ aspeed_video_set_resolution(video); + +- if (video->srcs[0].size) +- aspeed_video_free_buf(video, &video->srcs[0]); ++ video->pix_fmt.width = timings->width; ++ video->pix_fmt.height = timings->height; ++ video->pix_fmt.sizeimage = video->max_compressed_size; + } + + static void aspeed_video_update_regs(struct aspeed_video *video) +@@ -1219,6 +1688,8 @@ + u32 ctrl = 0; + u32 seq_ctrl = 0; + ++ v4l2_dbg(1, debug, &video->v4l2_dev, "input(%s)\n", ++ input_str[video->input]); + 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 @@ + else + aspeed_video_update(video, VE_BCD_CTRL, VE_BCD_CTRL_EN_BCD, 0); + ++ if (video->input == VIDEO_INPUT_VGA) ++ ctrl |= VE_CTRL_AUTO_OR_CURSOR; + -+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 (video->input == VIDEO_INPUT_DVI) ++ ctrl |= VE_CTRL_SOURCE; + -+ client = i3c_target_mctp_create_client(priv); -+ if (IS_ERR(client)) -+ return PTR_ERR(client); + if (video->frame_rate) + ctrl |= FIELD_PREP(VE_CTRL_FRC, video->frame_rate); + ++ if (video->format == VIDEO_FMT_PARTIAL) ++ ctrl |= video->compare_only; + -+ file->private_data = client; + if (video->format == VIDEO_FMT_STANDARD) { + comp_ctrl &= ~FIELD_PREP(VE_COMP_CTRL_EN_HQ, video->hq_mode); + seq_ctrl |= video->jpeg_mode; + } + ++ if (video->format != VIDEO_FMT_PARTIAL) ++ seq_ctrl |= VE_SEQ_CTRL_AUTO_COMP; + -+ return 0; -+} + if (video->yuv420) + seq_ctrl |= VE_SEQ_CTRL_YUV420; + +@@ -1252,7 +1735,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); + 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 @@ + aspeed_video_write(video, VE_COMP_OFFSET, 0); + + aspeed_video_write(video, VE_JPEG_ADDR, video->jpeg.dma); ++ aspeed_video_write(video, VE_BCD_ADDR, _make_addr(video->bcd.dma)); + + /* Set control registers */ ++ aspeed_video_write(video, VE_SEQ_CTRL, VE_SEQ_CTRL_AUTO_COMP); ++ if (video->version == 7) { ++ if (video->input == VIDEO_INPUT_DVI) ++ ctrl |= FIELD_PREP(VE_CTRL_CLK_DELAY, VIDEO_CLK_CRT2); ++ 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 @@ + aspeed_video_get_resolution(video); + + /* Set timings since the device is being opened for the first time */ +- video->active_timings = video->detected_timings; +- aspeed_video_set_resolution(video); +- +- video->pix_fmt.width = video->active_timings.width; +- video->pix_fmt.height = video->active_timings.height; +- video->pix_fmt.sizeimage = video->max_compressed_size; ++ aspeed_video_update_timings(video, &video->detected_timings); + } + + static void aspeed_video_stop(struct aspeed_video *video) +@@ -1326,15 +1814,6 @@ + + aspeed_video_off(video); + +- if (video->srcs[0].size) +- aspeed_video_free_buf(video, &video->srcs[0]); +- +- if (video->srcs[1].size) +- aspeed_video_free_buf(video, &video->srcs[1]); +- +- if (video->bcd.size) +- aspeed_video_free_buf(video, &video->bcd); +- + video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; + video->flags = 0; + } +@@ -1342,10 +1821,14 @@ + static int aspeed_video_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) + { ++ struct aspeed_video *video = video_drvdata(file); + -+static int i3c_target_mctp_release(struct inode *inode, struct file *file) -+{ -+ struct mctp_client *client = file->private_data; + strscpy(cap->driver, DEVICE_NAME, sizeof(cap->driver)); + strscpy(cap->card, "Aspeed Video Engine", sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + DEVICE_NAME); ++ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform: %s%d", ++ DEVICE_NAME, video->id); + + return 0; + } +@@ -1383,7 +1866,8 @@ + + switch (f->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_JPEG: +- video->format = VIDEO_FMT_STANDARD; ++ video->format = (f->fmt.pix.flags == V4L2_PIX_FMT_FLAG_PARTIAL_JPG) ++ ? VIDEO_FMT_PARTIAL : VIDEO_FMT_STANDARD; + break; + case V4L2_PIX_FMT_AJPG: + video->format = VIDEO_FMT_ASPEED; +@@ -1401,10 +1885,10 @@ + { + struct aspeed_video *video = video_drvdata(file); + +- if (inp->index) ++ if (inp->index >= VIDEO_INPUT_MAX) + return -EINVAL; + +- strscpy(inp->name, "Host VGA capture", sizeof(inp->name)); ++ sprintf(inp->name, "%s capture", input_str[inp->index]); + inp->type = V4L2_INPUT_TYPE_CAMERA; + inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; + inp->status = video->v4l2_input_status; +@@ -1414,15 +1898,116 @@ + + static int aspeed_video_get_input(struct file *file, void *fh, unsigned int *i) + { +- *i = 0; ++ struct aspeed_video *video = video_drvdata(file); + -+ i3c_target_mctp_delete_client(client); ++ *i = video->input; + + return 0; + } + + static int aspeed_video_set_input(struct file *file, void *fh, unsigned int i) + { +- if (i) ++ struct aspeed_video *video = video_drvdata(file); + -+ return 0; -+} ++ if (i >= VIDEO_INPUT_MAX) ++ return -EINVAL; + -+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; ++ if (i == video->input) ++ return 0; + -+ rx_packet = ptr_ring_consume_irq(&client->rx_queue); -+ if (!rx_packet) -+ return -EAGAIN; ++ if (vb2_is_busy(&video->queue)) ++ return -EBUSY; + -+ if (count < rx_packet->count) { -+ count = -EINVAL; -+ goto err_free; ++ if (IS_ERR(video->scu)) { ++ v4l2_dbg(1, debug, &video->v4l2_dev, "%s: scu isn't ready for input-control\n", __func__); + return -EINVAL; + } -+ 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); ++ 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 count; -+} ++ // prepare memory space for user to put test batch ++ if (i == VIDEO_INPUT_MEM && !video->dbg_src.size) { ++ if (!aspeed_video_alloc_buf(video, &video->dbg_src, VE_MAX_SRC_BUFFER_SIZE)) { ++ v4l2_err(&video->v4l2_dev, "Failed to allocate buffer for debug input\n"); ++ return -EINVAL; ++ } ++ v4l2_dbg(1, debug, &video->v4l2_dev, "dbg src addr(%pad) size(%d)\n", ++ &video->dbg_src.dma, video->dbg_src.size); ++ } ++ if (i != VIDEO_INPUT_MEM && video->dbg_src.size) ++ aspeed_video_free_buf(video, &video->dbg_src); + -+static u8 *pec_append(u8 addr_rnw, u8 *buf, u8 len) -+{ -+ u8 pec_v; ++ if (i == VIDEO_INPUT_DVI && video->version == 7) { ++ if (IS_ERR(video->dvi_base)) { ++ v4l2_err(&video->v4l2_dev, "%s: dvi isn't ready for DVI input\n", __func__); ++ return -EINVAL; ++ } + -+ pec_v = crc8(i3c_crc8_table, &addr_rnw, 1, 0); -+ pec_v = crc8(i3c_crc8_table, buf, len, pec_v); -+ buf[len] = pec_v; ++ /* Set DVI mode detection defaults */ ++ writel(FIELD_PREP(VE_MODE_DT_HOR_TOLER, 2) | ++ FIELD_PREP(VE_MODE_DT_VER_TOLER, 2) | ++ FIELD_PREP(VE_MODE_DT_HOR_STABLE, 6) | ++ FIELD_PREP(VE_MODE_DT_VER_STABLE, 6) | ++ FIELD_PREP(VE_MODE_DT_EDG_THROD, 0x65), ++ video->dvi_base + VE_MODE_DETECT); ++ } + -+ return buf; -+} ++ video->input = i; + -+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 (video->version == 6) { ++ /* modify dpll source per current input */ ++ if (video->input == VIDEO_INPUT_VGA) ++ regmap_update_bits(video->scu, SCU_MISC_CTRL, SCU_DPLL_SOURCE, 0); ++ else ++ regmap_update_bits(video->scu, SCU_MISC_CTRL, SCU_DPLL_SOURCE, SCU_DPLL_SOURCE); + -+ 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; ++ // SLI direction: inverse if DVI ++ if (video->input == VIDEO_INPUT_DVI) { ++ regmap_update_bits(video->scu, SCU_MULTI_FUNC_12, ++ SCU_MULTI_FUNC_CPU_SLI_DIR, ++ SCU_MULTI_FUNC_CPU_SLI_DIR); ++ regmap_update_bits(video->scu, SCU_MULTI_FUNC_15, ++ SCU_MULTI_FUNC_IO_SLI_DIR, ++ SCU_MULTI_FUNC_IO_SLI_DIR); ++ regmap_update_bits(video->scu, SCU_CLK_SEL2, ++ SCU_VIDEO_OUTPUT_DELAY, ++ 4); ++ } else { ++ regmap_update_bits(video->scu, SCU_MULTI_FUNC_12, ++ SCU_MULTI_FUNC_CPU_SLI_DIR, ++ 0); ++ regmap_update_bits(video->scu, SCU_MULTI_FUNC_15, ++ SCU_MULTI_FUNC_IO_SLI_DIR, ++ 0); ++ } ++ } else if (video->version == 7) { ++ if (video->input == VIDEO_INPUT_DVI) { ++ // CRT2CLK = 500 * R / N ++ regmap_write(video->scu, SCU_CRT2CLK, ++ FIELD_PREP(SCU_CRT2CLK_N, 50) | FIELD_PREP(SCU_CRT2CLK_R, 15)); + -+ tx_data = kzalloc(count, GFP_KERNEL); -+ if (!tx_data) { -+ ret = -ENOMEM; -+ goto free_ibi; ++ regmap_write(video->scu, SCU_CLK_SEL, FIELD_PREP(SCU_SOC_DISPLAY_SEL, 1)); ++ } else { ++ regmap_write(video->scu, SCU_CLK_SEL, FIELD_PREP(SCU_SOC_DISPLAY_SEL, 0)); ++ } + } + -+ if (copy_from_user(tx_data, buf, count)) { -+ ret = -EFAULT; -+ goto out_packet; -+ } ++ aspeed_video_update_regs(video); + -+ 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; ++ // update signal status ++ if (video->input == VIDEO_INPUT_MEM) { ++ video->v4l2_input_status = 0; + } else { -+ xfers[0].len = 1; ++ aspeed_video_get_resolution(video); ++ if (!video->v4l2_input_status) ++ aspeed_video_update_timings(video, &video->detected_timings); + } -+ 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; -+} ++ if (video->input == VIDEO_INPUT_MEM) ++ aspeed_video_start_frame(video); + + return 0; + } +@@ -1520,6 +2105,12 @@ + { + struct aspeed_video *video = video_drvdata(file); + ++ // if input is MEM, resolution decided by user ++ if (video->input == VIDEO_INPUT_MEM) { ++ video->detected_timings.width = timings->bt.width; ++ video->detected_timings.height = timings->bt.height; ++ } + -+static __poll_t i3c_target_mctp_poll(struct file *file, struct poll_table_struct *pt) + if (timings->bt.width == video->active_timings.width && + timings->bt.height == video->active_timings.height) + return 0; +@@ -1527,13 +2118,7 @@ + if (vb2_is_busy(&video->queue)) + return -EBUSY; + +- video->active_timings = timings->bt; +- +- aspeed_video_set_resolution(video); +- +- video->pix_fmt.width = timings->bt.width; +- video->pix_fmt.height = timings->bt.height; +- video->pix_fmt.sizeimage = video->max_compressed_size; ++ aspeed_video_update_timings(video, &timings->bt); + + timings->type = V4L2_DV_BT_656_1120; + +@@ -1589,6 +2174,37 @@ + NULL, NULL); + } + ++static int aspeed_video_g_selection(struct file *file, void *fh, ++ struct v4l2_selection *s) +{ -+ struct mctp_client *client = file->private_data; -+ __poll_t ret = 0; ++ struct aspeed_video *video = video_drvdata(file); ++ struct aspeed_video_box *box; ++ unsigned long flags; + -+ poll_wait(file, &client->wait_queue, pt); ++ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && ++ s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ++ return -EINVAL; + -+ if (__ptr_ring_peek(&client->rx_queue)) -+ ret |= EPOLLIN; ++ switch (s->target) { ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ spin_lock_irqsave(&video->lock, flags); ++ box = list_first_entry_or_null(&video->boxes, ++ struct aspeed_video_box, ++ link); ++ if (box) { ++ s->r = box->box; ++ list_del(&box->link); ++ kfree(box); ++ } else { ++ memset(&s->r, 0, sizeof(s->r)); ++ } ++ spin_unlock_irqrestore(&video->lock, flags); ++ return 0; ++ } + -+ /* -+ * 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; ++ return -EINVAL; +} + -+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 int aspeed_video_dv_timings_cap(struct file *file, void *fh, + struct v4l2_dv_timings_cap *cap) + { +@@ -1641,6 +2257,8 @@ + .vidioc_enum_dv_timings = aspeed_video_enum_dv_timings, + .vidioc_dv_timings_cap = aspeed_video_dv_timings_cap, + ++ .vidioc_g_selection = aspeed_video_g_selection, + -+static struct i3c_target_read_setup i3c_target_mctp_rx_packet_setup = { -+ .handler = i3c_target_mctp_rx_packet_enqueue, -+}; + .vidioc_subscribe_event = aspeed_video_sub_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + }; +@@ -1710,6 +2328,9 @@ + struct delayed_work *dwork = to_delayed_work(work); + struct aspeed_video *video = container_of(dwork, struct aspeed_video, + res_work); ++ bool is_res_chg = false; + -+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; ++ aspeed_video_reset(video); + + aspeed_video_on(video); + +@@ -1723,8 +2344,14 @@ + + aspeed_video_get_resolution(video); + +- if (video->detected_timings.width != video->active_timings.width || +- video->detected_timings.height != video->active_timings.height) { ++ if (video->v4l2_input_status) ++ goto done; + -+ ret = sysfs_emit(buf, "%d\n", priv->mdb_append_pec); ++ is_res_chg = (video->detected_timings.width != video->active_timings.width || ++ video->detected_timings.height != video->active_timings.height); ++ aspeed_video_update_timings(video, &video->detected_timings); + -+ return ret; ++ if (is_res_chg) { + static const struct v4l2_event ev = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, +@@ -1740,6 +2367,32 @@ + done: + clear_bit(VIDEO_RES_CHANGE, &video->flags); + wake_up_interruptible_all(&video->wait); ++ wake_up_all(&waitq); +} + -+static ssize_t mdb_append_pec_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t count) ++/* ++ * To mmap source memory for test from memory usage. ++ * test from memory input mode requires much bigger size because it is ++ * uncompressed BGRA format. Thus, We use VM_READ to tell it is for test ++ * or v4l2 now. ++ */ ++static int aspeed_video_mmap(struct file *file, struct vm_area_struct *vma) +{ -+ 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); ++ int rc; ++ struct aspeed_video *v = video_drvdata(file); ++ const size_t size = vma->vm_end - vma->vm_start; ++ const unsigned long pfn = __phys_to_pfn(v->dbg_src.dma); + -+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; ++ if (v->input != VIDEO_INPUT_MEM || vma->vm_flags & VM_READ) ++ return vb2_fop_mmap(file, vma); + -+ 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) { -+ ida_free(&i3c_target_mctp_ida, priv->id); -+ return ret; -+ } -+ -+ 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; -+ } -+ -+ /* -+ * 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; ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ rc = remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot); ++ if (rc) { ++ v4l2_err(&v->v4l2_dev, "remap_pfn_range failed(%d)\n", rc); ++ return -EAGAIN; + } -+ -+ 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: -+ cdev_del(&priv->cdev); -+ 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, i3c_target_mctp_devt); -+ 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/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 2026-04-08 18:03:48.116708865 +0000 -@@ -72,6 +72,8 @@ - #define ASPEED_ADC_BAT_SENSING_ENABLE BIT(13) - #define ASPEED_ADC_CTRL_CHANNEL GENMASK(31, 16) - #define ASPEED_ADC_CTRL_CHANNEL_ENABLE(ch) FIELD_PREP(ASPEED_ADC_CTRL_CHANNEL, BIT(ch)) -+#define ADC_MASK(n) ((n) < 16 ? ((1U << (n)) - 1) : 0xFFFF) -+#define ASPEED_ADC_CTRL_CHANNELS_ENABLE(chs) FIELD_PREP(ASPEED_ADC_CTRL_CHANNEL, ADC_MASK(chs)) + } - #define ASPEED_ADC_INIT_POLLING_TIME 500 - #define ASPEED_ADC_INIT_TIMEOUT 500000 -@@ -82,6 +84,8 @@ - */ - #define ASPEED_ADC_DEF_SAMPLING_RATE 65000 + static int aspeed_video_open(struct file *file) +@@ -1785,7 +2438,7 @@ + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, +- .mmap = vb2_fop_mmap, ++ .mmap = aspeed_video_mmap, + .open = aspeed_video_open, + .release = aspeed_video_release, + }; +@@ -1830,13 +2483,17 @@ + video->sequence = 0; + video->perf.duration_max = 0; + video->perf.duration_min = 0xffffffff; ++ set_bit(VIDEO_BOUNDING_BOX, &video->flags); -+static DEFINE_IDA(aspeed_adc_ida); -+ - struct aspeed_adc_trim_locate { - const unsigned int offset; - const unsigned int field; -@@ -95,6 +99,7 @@ - bool wait_init_sequence; - bool need_prescaler; - bool bat_sense_sup; -+ bool require_extra_eoc; - u8 scaler_bit_width; - unsigned int num_channels; - const struct aspeed_adc_trim_locate *trim_locate; -@@ -107,6 +112,7 @@ + aspeed_video_update_regs(video); - struct aspeed_adc_data { - struct device *dev; -+ int id; - const struct aspeed_adc_model_data *model_data; - void __iomem *base; - spinlock_t clk_lock; -@@ -119,6 +125,26 @@ - int cv; - bool battery_sensing; - struct adc_gain battery_mode_gain; -+ unsigned int required_eoc_num; -+ u16 *upper_bound; -+ u16 *lower_bound; -+ bool *upper_en; -+ bool *lower_en; -+}; -+ -+static const struct iio_event_spec aspeed_adc_events[] = { -+ { -+ .type = IIO_EV_TYPE_THRESH, -+ .dir = IIO_EV_DIR_RISING, -+ .mask_separate = -+ BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE), -+ }, -+ { -+ .type = IIO_EV_TYPE_THRESH, -+ .dir = IIO_EV_DIR_FALLING, -+ .mask_separate = -+ BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE), -+ }, - }; +- rc = aspeed_video_start_frame(video); +- if (rc) { +- aspeed_video_bufs_done(video, VB2_BUF_STATE_QUEUED); +- return rc; ++ // if input is MEM, don't start capture until user acquire ++ if (video->input != VIDEO_INPUT_MEM) { ++ rc = aspeed_video_start_frame(video); ++ if (rc) { ++ aspeed_video_bufs_done(video, VB2_BUF_STATE_QUEUED); ++ return rc; ++ } + } - #define ASPEED_CHAN(_idx, _data_reg_addr) { \ -@@ -130,6 +156,8 @@ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ - BIT(IIO_CHAN_INFO_OFFSET), \ -+ .event_spec = aspeed_adc_events, \ -+ .num_event_specs = ARRAY_SIZE(aspeed_adc_events), \ + set_bit(VIDEO_STREAMING, &video->flags); +@@ -1860,8 +2517,7 @@ + * Need to force stop any DMA and try and get HW into a good + * state for future calls to start streaming again. + */ +- aspeed_video_off(video); +- aspeed_video_on(video); ++ aspeed_video_reset(video); + + aspeed_video_init_regs(video); + +@@ -1885,7 +2541,8 @@ + spin_unlock_irqrestore(&video->lock, flags); + + if (test_bit(VIDEO_STREAMING, &video->flags) && +- !test_bit(VIDEO_FRAME_INPRG, &video->flags) && empty) ++ !test_bit(VIDEO_FRAME_INPRG, &video->flags) && empty && ++ (video->input != VIDEO_INPUT_MEM)) + aspeed_video_start_frame(video); } - static const struct iio_chan_spec aspeed_adc_iio_channels[] = { -@@ -174,18 +202,11 @@ +@@ -1911,6 +2568,7 @@ + val08 = aspeed_video_read(v, VE_CTRL); + if (FIELD_GET(VE_CTRL_DIRECT_FETCH, val08)) { + seq_printf(s, " %-20s:\tDirect fetch\n", "Mode"); ++ seq_printf(s, " %-20s:\t%s\n", "Input", input_str[v->input]); + seq_printf(s, " %-20s:\t%s\n", "VGA bpp mode", + FIELD_GET(VE_CTRL_INT_DE, val08) ? "16" : "32"); + } else { +@@ -1962,19 +2620,19 @@ + } + DEFINE_SHOW_ATTRIBUTE(aspeed_video_debugfs); - static int aspeed_adc_set_trim_data(struct iio_dev *indio_dev) +-static struct dentry *debugfs_entry; +- + static void aspeed_video_debugfs_remove(struct aspeed_video *video) { -- struct device_node *syscon; - struct regmap *scu; - u32 scu_otp, trimming_val; - struct aspeed_adc_data *data = iio_priv(indio_dev); +- debugfs_remove_recursive(debugfs_entry); +- debugfs_entry = NULL; ++ debugfs_remove_recursive(video->debugfs_entry); + } -- syscon = of_find_node_by_name(NULL, "syscon"); -- if (syscon == NULL) { -- dev_warn(data->dev, "Couldn't find syscon node\n"); -- return -EOPNOTSUPP; -- } -- scu = syscon_node_to_regmap(syscon); -- of_node_put(syscon); -+ scu = syscon_regmap_lookup_by_phandle(data->dev->of_node, "aspeed,scu"); - if (IS_ERR(scu)) { - dev_warn(data->dev, "Failed to get syscon regmap\n"); - return -EOPNOTSUPP; -@@ -276,36 +297,68 @@ + static void aspeed_video_debugfs_create(struct aspeed_video *video) + { +- debugfs_entry = debugfs_create_file(DEVICE_NAME, 0444, NULL, +- video, +- &aspeed_video_debugfs_fops); ++ char filename[16]; ++ ++ snprintf(filename, sizeof(filename), "%s%d", DEVICE_NAME, video->id); ++ video->debugfs_entry = debugfs_create_file(filename, 0444, ++ video->debugfs_entry, video, ++ &aspeed_video_debugfs_fops); + } + #else + static void aspeed_video_debugfs_remove(struct aspeed_video *video) { } +@@ -2028,6 +2686,8 @@ + vbq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vbq->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF; + vbq->dev = v4l2_dev->dev; ++ snprintf(vdev->name, sizeof(vdev->name), "%s%d", ++ DEVICE_NAME, video->id); + vbq->lock = &video->video_lock; + vbq->ops = &aspeed_video_vb2_ops; + vbq->mem_ops = &vb2_dma_contig_memops; +@@ -2070,11 +2730,30 @@ return 0; } -+static int aspeed_adc_get_voltage_raw(struct aspeed_adc_data *data, struct iio_chan_spec const *chan) ++/* ++ * Get regmap without checking res, such as clk/reset, that could lead to ++ * conflict. ++ */ ++static struct regmap *aspeed_regmap_lookup(struct device_node *np, const char *property) +{ -+ int val; ++ struct device_node *syscon_np __free(device_node) = of_parse_phandle(np, property, 0); + -+ val = readw(data->base + chan->address); -+ dev_dbg(data->dev, -+ "%d upper_bound: %d %x, lower_bound: %d %x, delay: %d * %d ns", -+ chan->channel, data->upper_en[chan->channel], -+ data->upper_bound[chan->channel], data->lower_en[chan->channel], -+ data->lower_bound[chan->channel], data->sample_period_ns, -+ data->required_eoc_num); -+ if (data->upper_en[chan->channel]) { -+ if (val >= data->upper_bound[chan->channel]) { -+ ndelay(data->sample_period_ns * -+ data->required_eoc_num); -+ val = readw(data->base + chan->address); -+ } -+ } -+ if (data->lower_en[chan->channel]) { -+ if (val <= data->lower_bound[chan->channel]) { -+ ndelay(data->sample_period_ns * -+ data->required_eoc_num); -+ val = readw(data->base + chan->address); -+ } -+ } -+ return val; ++ if (!syscon_np) ++ return ERR_PTR(-ENODEV); ++ ++ return device_node_to_regmap(syscon_np); +} + - static int aspeed_adc_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, long mask) + static int aspeed_video_init(struct aspeed_video *video) { - struct aspeed_adc_data *data = iio_priv(indio_dev); -- u32 adc_engine_control_reg_val; -+ u32 engine_ctrl_tmp_val, reg_val; + int irq; + int rc; + struct device *dev = video->dev; ++ unsigned int mask_size = (video->version >= 7) ? 64 : 32; ++ u32 resv_size = VE_MAX_SRC_BUFFER_SIZE * 2 + VE_JPEG_HEADER_SIZE + VE_BCD_BUFF_SIZE; ++ ++ video->scu = aspeed_regmap_lookup(dev->of_node, "aspeed,scu"); ++ video->gfx = aspeed_regmap_lookup(dev->of_node, "aspeed,gfx"); - switch (mask) { - case IIO_CHAN_INFO_RAW: -- if (data->battery_sensing && chan->channel == 7) { -- adc_engine_control_reg_val = -- readl(data->base + ASPEED_REG_ENGINE_CONTROL); -- writel(adc_engine_control_reg_val | -- FIELD_PREP(ASPEED_ADC_CH7_MODE, -- ASPEED_ADC_CH7_BAT) | -- ASPEED_ADC_BAT_SENSING_ENABLE, -- data->base + ASPEED_REG_ENGINE_CONTROL); -+ if (data->model_data->bat_sense_sup && -+ chan->channel == data->model_data->num_channels - 1) { -+ engine_ctrl_tmp_val = readl(data->base + ASPEED_REG_ENGINE_CONTROL); -+ reg_val = engine_ctrl_tmp_val & -+ ~ASPEED_ADC_CTRL_CHANNELS_ENABLE(data->model_data->num_channels); -+ reg_val |= ASPEED_ADC_CTRL_CHANNEL_ENABLE(chan->channel); -+ if (data->battery_sensing) -+ reg_val |= FIELD_PREP(ASPEED_ADC_CH7_MODE, ASPEED_ADC_CH7_BAT) | -+ ASPEED_ADC_BAT_SENSING_ENABLE; -+ writel(reg_val, data->base + ASPEED_REG_ENGINE_CONTROL); - /* - * After enable battery sensing mode need to wait some time for adc stable - * Experiment result is 1ms. - */ - mdelay(1); -- *val = readw(data->base + chan->address); -- *val = (*val * data->battery_mode_gain.mult) / -- data->battery_mode_gain.div; -+ *val = aspeed_adc_get_voltage_raw(data, chan); -+ if (data->battery_sensing) -+ *val = (*val * data->battery_mode_gain.mult) / -+ data->battery_mode_gain.div; - /* Restore control register value */ -- writel(adc_engine_control_reg_val, -+ writel(engine_ctrl_tmp_val, - data->base + ASPEED_REG_ENGINE_CONTROL); -- } else -- *val = readw(data->base + chan->address); -+ } else { -+ *val = aspeed_adc_get_voltage_raw(data, chan); -+ } - return IIO_VAL_INT; + irq = irq_of_parse_and_map(dev->of_node, 0); + if (!irq) { +@@ -2082,14 +2761,36 @@ + return -ENODEV; + } - case IIO_CHAN_INFO_OFFSET: -@@ -368,9 +421,106 @@ - return 0; - } +- rc = devm_request_threaded_irq(dev, irq, NULL, aspeed_video_irq, +- IRQF_ONESHOT, DEVICE_NAME, video); ++ rc = devm_request_threaded_irq(dev, irq, aspeed_video_irq, ++ aspeed_video_thread_irq, ++ IRQF_ONESHOT, dev_name(dev), video); + if (rc < 0) { + dev_err(dev, "Unable to request IRQ %d\n", irq); + return rc; + } + dev_info(video->dev, "irq %d\n", irq); -+static int aspeed_adc_read_event_config(struct iio_dev *indio_dev, -+ const struct iio_chan_spec *chan, -+ enum iio_event_type type, -+ enum iio_event_direction dir) -+{ -+ struct aspeed_adc_data *data = iio_priv(indio_dev); -+ -+ switch (dir) { -+ case IIO_EV_DIR_RISING: -+ return data->upper_en[chan->channel]; -+ case IIO_EV_DIR_FALLING: -+ return data->lower_en[chan->channel]; -+ default: -+ return -EINVAL; -+ } -+} -+ -+static int aspeed_adc_write_event_config(struct iio_dev *indio_dev, -+ const struct iio_chan_spec *chan, -+ enum iio_event_type type, -+ enum iio_event_direction dir, -+ int state) -+{ -+ struct aspeed_adc_data *data = iio_priv(indio_dev); ++ if (!IS_ERR(video->dvi_base)) { ++ irq = irq_of_parse_and_map(dev->of_node, 1); ++ if (!irq) { ++ dev_err(dev, "Unable to find DVI IRQ\n"); ++ return -ENODEV; ++ } + -+ switch (dir) { -+ case IIO_EV_DIR_RISING: -+ data->upper_en[chan->channel] = state ? 1 : 0; -+ break; -+ case IIO_EV_DIR_FALLING: -+ data->lower_en[chan->channel] = state ? 1 : 0; -+ break; -+ default: -+ return -EINVAL; ++ rc = devm_request_irq(dev, irq, aspeed_video_md_irq, 0, dev_name(dev), video); ++ if (rc < 0) { ++ dev_err(dev, "Unable to request DVI IRQ %d\n", irq); ++ return rc; ++ } ++ dev_info(video->dev, "dvi mode-detection irq %d\n", irq); + } + -+ return 0; -+} -+ -+static int aspeed_adc_write_event_value(struct iio_dev *indio_dev, -+ const struct iio_chan_spec *chan, -+ enum iio_event_type type, -+ enum iio_event_direction dir, -+ enum iio_event_info info, int val, -+ int val2) -+{ -+ struct aspeed_adc_data *data = iio_priv(indio_dev); -+ -+ if (info != IIO_EV_INFO_VALUE) -+ return -EINVAL; -+ -+ switch (dir) { -+ case IIO_EV_DIR_RISING: -+ if (val >= BIT(ASPEED_RESOLUTION_BITS)) -+ return -EINVAL; -+ data->upper_bound[chan->channel] = val; -+ break; -+ case IIO_EV_DIR_FALLING: -+ data->lower_bound[chan->channel] = val; -+ break; -+ default: -+ return -EINVAL; ++ video->reset = devm_reset_control_get_shared(dev, NULL); ++ if (IS_ERR(video->reset)) { ++ dev_err(dev, "Unable to get reset\n"); ++ return PTR_ERR(video->reset); + } + -+ return 0; -+} -+ -+static int aspeed_adc_read_event_value(struct iio_dev *indio_dev, -+ const struct iio_chan_spec *chan, -+ enum iio_event_type type, -+ enum iio_event_direction dir, -+ enum iio_event_info info, int *val, -+ int *val2) -+{ -+ struct aspeed_adc_data *data = iio_priv(indio_dev); -+ -+ if (info != IIO_EV_INFO_VALUE) -+ return -EINVAL; + video->eclk = devm_clk_get(dev, "eclk"); + if (IS_ERR(video->eclk)) { + dev_err(dev, "Unable to get ECLK\n"); +@@ -2111,22 +2812,53 @@ + if (rc) + goto err_unprepare_eclk; + ++ if (video->version > 6) { ++ video->crt2clk = devm_clk_get(dev, "crt2clk"); ++ if (IS_ERR(video->crt2clk)) { ++ dev_err(dev, "Unable to get CRT2CLK\n"); ++ rc = PTR_ERR(video->crt2clk); ++ goto err_unprepare_vclk; ++ } + -+ switch (dir) { -+ case IIO_EV_DIR_RISING: -+ *val = data->upper_bound[chan->channel]; -+ break; -+ case IIO_EV_DIR_FALLING: -+ *val = data->lower_bound[chan->channel]; -+ break; -+ default: -+ return -EINVAL; ++ rc = clk_prepare_enable(video->crt2clk); ++ if (rc) ++ goto err_unprepare_vclk; + } + -+ return IIO_VAL_INT; -+} -+ - static const struct iio_info aspeed_adc_iio_info = { - .read_raw = aspeed_adc_read_raw, - .write_raw = aspeed_adc_write_raw, -+ .read_event_config = &aspeed_adc_read_event_config, -+ .write_event_config = &aspeed_adc_write_event_config, -+ .read_event_value = &aspeed_adc_read_event_value, -+ .write_event_value = &aspeed_adc_write_event_value, - .debugfs_reg_access = aspeed_adc_reg_access, - }; + of_reserved_mem_device_init(dev); -@@ -381,6 +531,13 @@ - clk_hw_unregister_fixed_factor(clk); - } +- rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); ++ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(mask_size)); + if (rc) { + dev_err(dev, "Failed to set DMA mask\n"); + goto err_release_reserved_mem; + } -+static void aspeed_adc_ida_remove(void *data) -+{ -+ struct aspeed_adc_data *priv_data = data; -+ -+ ida_simple_remove(&aspeed_adc_ida, priv_data->id); -+} -+ - static void aspeed_adc_reset_assert(void *data) - { - struct reset_control *rst = data; -@@ -415,6 +572,7 @@ +- if (!aspeed_video_alloc_buf(video, &video->jpeg, +- VE_JPEG_HEADER_SIZE)) { +- dev_err(dev, "Failed to allocate DMA for JPEG header\n"); ++ if (!aspeed_video_alloc_buf(video, &video->pool, resv_size)) { ++ dev_err(dev, "Failed to allocate DMA pool\n"); + rc = -ENOMEM; + goto err_release_reserved_mem; } - adc_engine_control_reg_val = - readl(data->base + ASPEED_REG_ENGINE_CONTROL); -+ adc_engine_control_reg_val &= ~ASPEED_ADC_REF_VOLTAGE; +- dev_info(video->dev, "alloc mem size(%d) at %pad for jpeg header\n", +- VE_JPEG_HEADER_SIZE, &video->jpeg.dma); ++ video->jpeg.size = VE_JPEG_HEADER_SIZE; ++ video->jpeg.virt = video->pool.virt; ++ video->jpeg.dma = video->pool.dma; ++ video->bcd.size = VE_BCD_BUFF_SIZE; ++ video->bcd.virt = video->jpeg.virt + video->jpeg.size; ++ video->bcd.dma = video->jpeg.dma + video->jpeg.size; ++ video->srcs[0].size = VE_MAX_SRC_BUFFER_SIZE; ++ video->srcs[0].dma = video->bcd.dma + video->bcd.size; ++ video->srcs[1].size = VE_MAX_SRC_BUFFER_SIZE; ++ video->srcs[1].dma = video->srcs[0].dma + video->srcs[0].size; ++ ++ dev_info(video->dev, "alloc mem size(%d) at %pad for pool\n", ++ resv_size, &video->pool.dma); ++ v4l2_dbg(1, debug, &video->v4l2_dev, "jpeg header addr(%pad) size(%d)\n", ++ &video->jpeg.dma, video->jpeg.size); ++ v4l2_dbg(1, debug, &video->v4l2_dev, "bcd addr(%pad) size(%d)\n", ++ &video->bcd.dma, video->bcd.size); ++ v4l2_dbg(1, debug, &video->v4l2_dev, "src buf0 addr(%pad) size(%d)\n", ++ &video->srcs[0].dma, video->srcs[0].size); ++ v4l2_dbg(1, debug, &video->v4l2_dev, "src buf1 addr(%pad) size(%d)\n", ++ &video->srcs[1].dma, video->srcs[1].size); - ret = devm_regulator_get_enable_read_voltage(data->dev, "vref"); - if (ret < 0 && ret != -ENODEV) -@@ -474,6 +632,7 @@ - u32 adc_engine_control_reg_val; - unsigned long scaler_flags = 0; - char clk_name[32], clk_parent_name[32]; -+ const char *model_name; + aspeed_video_init_jpeg_table(video->jpeg.virt, video->yuv420); - indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*data)); - if (!indio_dev) -@@ -488,12 +647,44 @@ - if (IS_ERR(data->base)) - return PTR_ERR(data->base); +@@ -2134,6 +2866,9 @@ -+ data->upper_bound = devm_kzalloc(&pdev->dev, -+ sizeof(data->upper_bound) * -+ data->model_data->num_channels, -+ GFP_KERNEL); -+ if (!data->upper_bound) -+ return -ENOMEM; -+ data->upper_en = devm_kzalloc(&pdev->dev, -+ sizeof(data->upper_en) * -+ data->model_data->num_channels, -+ GFP_KERNEL); -+ if (!data->upper_en) -+ return -ENOMEM; -+ data->lower_bound = devm_kzalloc(&pdev->dev, -+ sizeof(data->lower_bound) * -+ data->model_data->num_channels, -+ GFP_KERNEL); -+ if (!data->lower_bound) -+ return -ENOMEM; -+ data->lower_en = devm_kzalloc(&pdev->dev, -+ sizeof(data->lower_en) * -+ data->model_data->num_channels, -+ GFP_KERNEL); -+ if (!data->lower_en) -+ return -ENOMEM; -+ data->id = ida_simple_get(&aspeed_adc_ida, 0, 0, GFP_KERNEL); -+ if (data->id < 0) -+ return data->id; -+ ret = devm_add_action_or_reset(data->dev, aspeed_adc_ida_remove, data); -+ if (ret) -+ return ret; -+ model_name = kasprintf(GFP_KERNEL, "%s-%d", -+ data->model_data->model_name, data->id); - /* Register ADC clock prescaler with source specified by device tree. */ - spin_lock_init(&data->clk_lock); - snprintf(clk_parent_name, ARRAY_SIZE(clk_parent_name), "%s", - of_clk_get_parent_name(pdev->dev.of_node, 0)); - snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-fixed-div", -- data->model_data->model_name); -+ model_name); - 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 @@ + err_release_reserved_mem: + of_reserved_mem_device_release(dev); ++ if (!IS_ERR(video->crt2clk)) ++ clk_disable_unprepare(video->crt2clk); ++err_unprepare_vclk: + clk_unprepare(video->vclk); + err_unprepare_eclk: + clk_unprepare(video->eclk); +@@ -2145,6 +2880,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 }, ++ { .compatible = "aspeed,ast2700-video-engine", .data = &ast2700_config }, + {} + }; + MODULE_DEVICE_TABLE(of, aspeed_video_of_match); +@@ -2159,6 +2895,10 @@ + if (!video) + return -ENOMEM; - if (data->model_data->need_prescaler) { - snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-prescaler", -- data->model_data->model_name); -+ model_name); - 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 @@ - * setting to adjust the prescaler as well. - */ - snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-scaler", -- data->model_data->model_name); -+ model_name); - 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 @@ ++ video->id = of_alias_get_id(pdev->dev.of_node, "video"); ++ if (video->id < 0) ++ video->id = 0; ++ + video->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(video->base)) + return PTR_ERR(video->base); +@@ -2167,8 +2907,10 @@ + if (!config) + return -ENODEV; - aspeed_adc_compensation(indio_dev); - /* Start all channels in normal mode. */ -- adc_engine_control_reg_val = -- readl(data->base + ASPEED_REG_ENGINE_CONTROL); -- adc_engine_control_reg_val |= ASPEED_ADC_CTRL_CHANNEL; -+ adc_engine_control_reg_val = readl(data->base + ASPEED_REG_ENGINE_CONTROL); -+ /* Disable the last channel when the controller supports battery sensing */ -+ if (data->model_data->bat_sense_sup) -+ adc_engine_control_reg_val |= -+ ASPEED_ADC_CTRL_CHANNELS_ENABLE(data->model_data->num_channels - 1); -+ else -+ adc_engine_control_reg_val |= -+ ASPEED_ADC_CTRL_CHANNELS_ENABLE(data->model_data->num_channels); - writel(adc_engine_control_reg_val, - data->base + ASPEED_REG_ENGINE_CONTROL); -- -- indio_dev->name = data->model_data->model_name; -+ adc_engine_control_reg_val = -+ FIELD_GET(ASPEED_ADC_CTRL_CHANNEL, -+ readl(data->base + ASPEED_REG_ENGINE_CONTROL)); -+ data->required_eoc_num = hweight_long(adc_engine_control_reg_val); -+ if (data->model_data->require_extra_eoc && -+ (adc_engine_control_reg_val & -+ BIT(data->model_data->num_channels - 1))) -+ data->required_eoc_num += 12; -+ indio_dev->name = model_name; - indio_dev->info = &aspeed_adc_iio_info; - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = data->battery_sensing ? -@@ -645,6 +848,16 @@ - .field = GENMASK(7, 4), - }; ++ video->version = config->version; + video->jpeg_mode = config->jpeg_mode; + video->comp_size_read = config->comp_size_read; ++ video->compare_only = config->compare_only; -+static const struct aspeed_adc_trim_locate ast2700_adc0_trim = { -+ .offset = 0x820, -+ .field = GENMASK(3, 0), -+}; + video->frame_rate = 30; + video->jpeg_hq_quality = 1; +@@ -2178,6 +2920,19 @@ + init_waitqueue_head(&video->wait); + INIT_DELAYED_WORK(&video->res_work, aspeed_video_resolution_work); + INIT_LIST_HEAD(&video->buffers); ++ INIT_LIST_HEAD(&video->boxes); + -+static const struct aspeed_adc_trim_locate ast2700_adc1_trim = { -+ .offset = 0x820, -+ .field = GENMASK(7, 4), -+}; ++ video->rst_wq = create_singlethread_workqueue("video_rst_wq"); ++ if (!video->rst_wq) { ++ dev_err(&pdev->dev, "unable to alloc rst workqueue\n"); ++ return -ENOMEM; ++ } ++ INIT_WORK(&video->rst_work, aspeed_video_rst_worker); + - static const struct aspeed_adc_model_data ast2400_model_data = { - .model_name = "ast2400-adc", - .vref_fixed_mv = 2500, -@@ -653,6 +866,7 @@ - .need_prescaler = true, - .scaler_bit_width = 10, - .num_channels = 16, -+ .require_extra_eoc = 0, - }; ++ if (video->version == 7 && video->id == 0) ++ video->dvi_base = devm_platform_ioremap_resource(pdev, 1); ++ else ++ video->dvi_base = ERR_PTR(-ENODEV); - static const struct aspeed_adc_model_data ast2500_model_data = { -@@ -665,6 +879,7 @@ - .scaler_bit_width = 10, - .num_channels = 16, - .trim_locate = &ast2500_adc_trim, -+ .require_extra_eoc = 0, - }; + rc = aspeed_video_init(video); + if (rc) +@@ -2185,7 +2940,6 @@ - static const struct aspeed_adc_model_data ast2600_adc0_model_data = { -@@ -676,6 +891,7 @@ - .scaler_bit_width = 16, - .num_channels = 8, - .trim_locate = &ast2600_adc0_trim, -+ .require_extra_eoc = 1, - }; + 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 @@ - static const struct aspeed_adc_model_data ast2600_adc1_model_data = { -@@ -687,6 +903,29 @@ - .scaler_bit_width = 16, - .num_channels = 8, - .trim_locate = &ast2600_adc1_trim, -+ .require_extra_eoc = 1, -+}; -+ -+static const struct aspeed_adc_model_data ast2700_adc0_model_data = { -+ .model_name = "ast2700-adc0", -+ .min_sampling_rate = 10000, -+ .max_sampling_rate = 500000, -+ .wait_init_sequence = true, -+ .bat_sense_sup = true, -+ .scaler_bit_width = 16, -+ .num_channels = 8, -+ .trim_locate = &ast2700_adc0_trim, -+}; -+ -+static const struct aspeed_adc_model_data ast2700_adc1_model_data = { -+ .model_name = "ast2700-adc1", -+ .min_sampling_rate = 10000, -+ .max_sampling_rate = 500000, -+ .wait_init_sequence = true, -+ .bat_sense_sup = true, -+ .scaler_bit_width = 16, -+ .num_channels = 8, -+ .trim_locate = &ast2700_adc1_trim, - }; + aspeed_video_debugfs_create(video); - static const struct of_device_id aspeed_adc_matches[] = { -@@ -694,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 }, -+ { .compatible = "aspeed,ast2700-adc0", .data = &ast2700_adc0_model_data }, -+ { .compatible = "aspeed,ast2700-adc1", .data = &ast2700_adc1_model_data }, - { } - }; - MODULE_DEVICE_TABLE(of, aspeed_adc_matches); -diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig ---- a/drivers/irqchip/Kconfig 2026-04-08 18:03:23.262162447 +0000 -+++ b/drivers/irqchip/Kconfig 2026-04-08 18:03:34.708953665 +0000 -@@ -734,6 +734,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-04-08 18:03:23.262162447 +0000 -+++ b/drivers/irqchip/Makefile 2026-04-08 18:03:39.587864679 +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/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 2026-04-08 18:03:48.342704735 +0000 -@@ -0,0 +1,178 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Aspeed AST27XX E2M Interrupt Controller -+ * Copyright (C) 2023 ASPEED Technology Inc. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define ASPEED_AST2700_E2M_IC_SHIFT 0 -+#define ASPEED_AST2700_E2M_IC_ENABLE \ -+ GENMASK(7, ASPEED_AST2700_E2M_IC_SHIFT) -+#define ASPEED_AST2700_E2M_IC_NUM_IRQS 8 -+#define ASPEED_AST2700_E2M_IC_EN_REG 0x14 -+#define ASPEED_AST2700_E2M_IC_STS_REG 0x18 -+ -+struct aspeed_e2m_ic { -+ unsigned long irq_enable; -+ unsigned long irq_shift; -+ unsigned int num_irqs; -+ unsigned int reg; -+ unsigned int en_reg; -+ unsigned int sts_reg; -+ struct regmap *e2m; -+ struct irq_domain *irq_domain; -+}; -+ -+static void aspeed_e2m_ic_irq_handler(struct irq_desc *desc) -+{ -+ unsigned int val; -+ unsigned long bit; -+ unsigned long enabled; -+ unsigned long max; -+ unsigned long status; -+ struct aspeed_e2m_ic *e2m_ic = irq_desc_get_handler_data(desc); -+ struct irq_chip *chip = irq_desc_get_chip(desc); -+ unsigned int mask; -+ -+ chained_irq_enter(chip, desc); -+ -+ mask = e2m_ic->irq_enable; -+ regmap_read(e2m_ic->e2m, e2m_ic->en_reg, &val); -+ enabled = val & e2m_ic->irq_enable; -+ regmap_read(e2m_ic->e2m, e2m_ic->sts_reg, &val); -+ status = val & enabled; -+ -+ bit = e2m_ic->irq_shift; -+ max = e2m_ic->num_irqs + bit; -+ -+ for_each_set_bit_from(bit, &status, max) { -+ generic_handle_domain_irq(e2m_ic->irq_domain, bit - e2m_ic->irq_shift); -+ -+ regmap_write_bits(e2m_ic->e2m, e2m_ic->sts_reg, mask, BIT(bit)); -+ } -+ -+ chained_irq_exit(chip, desc); -+} -+ -+static void aspeed_e2m_ic_irq_mask(struct irq_data *data) -+{ -+ struct aspeed_e2m_ic *e2m_ic = irq_data_get_irq_chip_data(data); -+ unsigned int mask; ++ dev_info(video->dev, "%s%d registered as /dev/video%d\n", DEVICE_NAME, ++ video->id, video->vdev.num); + -+ mask = BIT(data->hwirq + e2m_ic->irq_shift); -+ regmap_update_bits(e2m_ic->e2m, e2m_ic->en_reg, mask, 0); -+} + return 0; + } + +@@ -2204,8 +2961,12 @@ + + aspeed_video_off(video); + ++ destroy_workqueue(video->rst_wq); + -+static void aspeed_e2m_ic_irq_unmask(struct irq_data *data) -+{ -+ struct aspeed_e2m_ic *e2m_ic = irq_data_get_irq_chip_data(data); -+ unsigned int bit = BIT(data->hwirq + e2m_ic->irq_shift); -+ unsigned int mask; + aspeed_video_debugfs_remove(video); + ++ if (!IS_ERR(video->crt2clk)) ++ clk_disable_unprepare(video->crt2clk); + clk_unprepare(video->vclk); + clk_unprepare(video->eclk); + +@@ -2215,7 +2976,7 @@ + + v4l2_device_unregister(v4l2_dev); + +- aspeed_video_free_buf(video, &video->jpeg); ++ aspeed_video_free_buf(video, &video->pool); + + 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 +@@ -11,8 +11,10 @@ + #include + #include + #include ++#include + #include + #include ++#include + #include + + #include "sdhci-pltfm.h" +@@ -23,6 +25,8 @@ + #define ASPEED_SDC_PHASE 0xf4 + #define ASPEED_SDC_S1_PHASE_IN GENMASK(25, 21) + #define ASPEED_SDC_S0_PHASE_IN GENMASK(20, 16) ++#define ASPEED_SDC_S0_PHASE_IN_SHIFT 16 ++#define ASPEED_SDC_S0_PHASE_OUT_SHIFT 3 + #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 @@ + #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 + -+ mask = bit; -+ regmap_update_bits(e2m_ic->e2m, e2m_ic->en_reg, mask, bit); -+} + /* SDIO{10,20} */ +-#define ASPEED_SDC_CAP1_1_8V (0 * 32 + 26) ++#define ASPEED_SDC_CAP1_1_8V (0 * 32 + 26) + /* SDIO{14,24} */ +-#define ASPEED_SDC_CAP2_SDR104 (1 * 32 + 1) ++#define ASPEED_SDC_CAP2_SDR104 (1 * 32 + 1) + -+static int aspeed_e2m_ic_irq_set_affinity(struct irq_data *data, -+ const struct cpumask *dest, -+ bool force) -+{ -+ return -EINVAL; -+} ++#define PROBE_AFTER_ASSET_DEASSERT 0x1 + -+static struct irq_chip aspeed_scu_ic_chip = { -+ .name = "aspeed-e2m-ic", -+ .irq_mask = aspeed_e2m_ic_irq_mask, -+ .irq_unmask = aspeed_e2m_ic_irq_unmask, -+ .irq_set_affinity = aspeed_e2m_ic_irq_set_affinity, ++struct aspeed_sdc_info { ++ u32 flag; +}; -+ -+static int aspeed_e2m_ic_map(struct irq_domain *domain, unsigned int irq, -+ irq_hw_number_t hwirq) -+{ -+ irq_set_chip_and_handler(irq, &aspeed_scu_ic_chip, handle_level_irq); -+ irq_set_chip_data(irq, domain->host_data); -+ -+ return 0; -+} -+ -+static const struct irq_domain_ops aspeed_e2m_ic_domain_ops = { -+ .map = aspeed_e2m_ic_map, + + struct aspeed_sdc { + struct clk *clk; + struct resource *res; ++ struct reset_control *rst; + + spinlock_t lock; + void __iomem *regs; + }; + +-struct aspeed_sdhci_tap_param { +- bool valid; +- +-#define ASPEED_SDHCI_TAP_PARAM_INVERT_CLK BIT(4) +- u8 in; +- u8 out; +-}; +- +-struct aspeed_sdhci_tap_desc { +- u32 tap_mask; +- u32 enable_mask; +- u8 enable_value; +-}; +- +-struct aspeed_sdhci_phase_desc { +- struct aspeed_sdhci_tap_desc in; +- struct aspeed_sdhci_tap_desc out; +-}; +- + struct aspeed_sdhci_pdata { + unsigned int clk_div_start; +- const struct aspeed_sdhci_phase_desc *phase_desc; +- size_t nr_phase_descs; + }; + + struct aspeed_sdhci { + const struct aspeed_sdhci_pdata *pdata; + struct aspeed_sdc *parent; + u32 width_mask; +- struct mmc_clk_phase_map phase_map; +- const struct aspeed_sdhci_phase_desc *phase_desc; +}; + -+static int aspeed_e2m_ic_of_init_common(struct aspeed_e2m_ic *e2m_ic, -+ struct device_node *node) -+{ -+ int irq; -+ int rc = 0; -+ -+ if (!node->parent) { -+ rc = -ENODEV; -+ goto err; -+ } -+ -+ e2m_ic->e2m = syscon_node_to_regmap(node->parent); -+ if (IS_ERR(e2m_ic->e2m)) { -+ rc = PTR_ERR(e2m_ic->e2m); -+ goto err; -+ } -+ -+ /* Clear status and disable all interrupt */ -+ regmap_write_bits(e2m_ic->e2m, e2m_ic->sts_reg, -+ e2m_ic->irq_enable, e2m_ic->irq_enable); -+ regmap_write_bits(e2m_ic->e2m, e2m_ic->en_reg, -+ e2m_ic->irq_enable, 0); -+ -+ irq = irq_of_parse_and_map(node, 0); -+ if (!irq) { -+ rc = -EINVAL; -+ goto err; -+ } -+ -+ e2m_ic->irq_domain = irq_domain_add_linear(node, e2m_ic->num_irqs, -+ &aspeed_e2m_ic_domain_ops, -+ e2m_ic); -+ if (!e2m_ic->irq_domain) { -+ rc = -ENOMEM; -+ goto err; -+ } -+ -+ irq_set_chained_handler_and_data(irq, aspeed_e2m_ic_irq_handler, -+ e2m_ic); -+ -+ return 0; -+ -+err: -+ kfree(e2m_ic); -+ -+ return rc; -+} -+ -+static int __init aspeed_ast2700_e2m_ic_of_init(struct device_node *node, -+ struct device_node *parent) -+{ -+ struct aspeed_e2m_ic *e2m_ic = kzalloc(sizeof(*e2m_ic), GFP_KERNEL); -+ -+ if (!e2m_ic) -+ return -ENOMEM; -+ -+ e2m_ic->irq_enable = ASPEED_AST2700_E2M_IC_ENABLE; -+ e2m_ic->irq_shift = ASPEED_AST2700_E2M_IC_SHIFT; -+ e2m_ic->num_irqs = ASPEED_AST2700_E2M_IC_NUM_IRQS; -+ e2m_ic->en_reg = ASPEED_AST2700_E2M_IC_EN_REG; -+ e2m_ic->sts_reg = ASPEED_AST2700_E2M_IC_STS_REG; -+ -+ return aspeed_e2m_ic_of_init_common(e2m_ic, node); -+} -+ -+IRQCHIP_DECLARE(ast2700_e2m_ic, "aspeed,ast2700-e2m-ic", -+ 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 2026-04-08 18:03:48.349704608 +0000 -@@ -0,0 +1,188 @@ -+// 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 INTC_INT_ENABLE_REG 0x00 -+#define INTC_INT_STATUS_REG 0x04 -+#define INTC_IRQS_PER_WORD 32 -+#define INTC_IRQ_BASE 192 -+ -+struct aspeed_intc_ic { -+ void __iomem *base; -+ raw_spinlock_t intc_lock; -+ struct irq_domain *irq_domain; -+}; -+ -+static void aspeed_intc0_ic_irq_handler(struct irq_desc *desc) ++static struct aspeed_sdc_info ast2600_sdc_info = { ++ .flag = PROBE_AFTER_ASSET_DEASSERT + }; + + /* + * The function sets the mirror register for updating + * capbilities of the current slot. + * +- * slot | capability | caps_reg | mirror_reg ++ * slot | capability | caps_reg | mirror_reg + * -----|-------------|----------|------------ +- * 0 | CAP1_1_8V | SDIO140 | SDIO10 ++ * 0 | CAP1_1_8V | SDIO140 | SDIO10 + * 0 | CAP2_SDR104 | SDIO144 | SDIO14 +- * 1 | CAP1_1_8V | SDIO240 | SDIO20 ++ * 1 | CAP1_1_8V | SDIO240 | SDIO20 + * 1 | CAP2_SDR104 | SDIO244 | SDIO24 + */ + static void aspeed_sdc_set_slot_capability(struct sdhci_host *host, struct aspeed_sdc *sdc, +@@ -125,222 +120,217 @@ + spin_unlock(&sdc->lock); + } + +-static u32 +-aspeed_sdc_set_phase_tap(const struct aspeed_sdhci_tap_desc *desc, +- u8 tap, bool enable, u32 reg) +-{ +- reg &= ~(desc->enable_mask | desc->tap_mask); +- if (enable) { +- reg |= tap << __ffs(desc->tap_mask); +- reg |= desc->enable_value << __ffs(desc->enable_mask); +- } +- +- return reg; +-} +- +-static void +-aspeed_sdc_set_phase_taps(struct aspeed_sdc *sdc, +- const struct aspeed_sdhci_phase_desc *desc, +- const struct aspeed_sdhci_tap_param *taps) ++static void aspeed_sdhci_set_bus_width(struct sdhci_host *host, int width) + { +- u32 reg; ++ struct sdhci_pltfm_host *pltfm_priv; ++ struct aspeed_sdhci *aspeed_sdhci; ++ struct aspeed_sdc *aspeed_sdc; ++ u8 ctrl; + +- spin_lock(&sdc->lock); +- reg = readl(sdc->regs + ASPEED_SDC_PHASE); ++ pltfm_priv = sdhci_priv(host); ++ aspeed_sdhci = sdhci_pltfm_priv(pltfm_priv); ++ aspeed_sdc = aspeed_sdhci->parent; + +- reg = aspeed_sdc_set_phase_tap(&desc->in, taps->in, taps->valid, reg); +- reg = aspeed_sdc_set_phase_tap(&desc->out, taps->out, taps->valid, reg); ++ /* Set/clear 8-bit mode */ ++ aspeed_sdc_configure_8bit_mode(aspeed_sdc, aspeed_sdhci, ++ width == MMC_BUS_WIDTH_8); + +- writel(reg, sdc->regs + ASPEED_SDC_PHASE); +- spin_unlock(&sdc->lock); ++ /* Set/clear 1 or 4 bit mode */ ++ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); ++ if (width == MMC_BUS_WIDTH_4) ++ ctrl |= SDHCI_CTRL_4BITBUS; ++ else ++ ctrl &= ~SDHCI_CTRL_4BITBUS; ++ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); + } + +-#define PICOSECONDS_PER_SECOND 1000000000000ULL +-#define ASPEED_SDHCI_NR_TAPS 15 +-/* Measured value with *handwave* environmentals and static loading */ +-#define ASPEED_SDHCI_MAX_TAP_DELAY_PS 1253 +-static int aspeed_sdhci_phase_to_tap(struct device *dev, unsigned long rate_hz, +- int phase_deg) +-{ +- u64 phase_period_ps; +- u64 prop_delay_ps; +- u64 clk_period_ps; +- unsigned int tap; +- u8 inverted; +- +- phase_deg %= 360; +- +- if (phase_deg >= 180) { +- inverted = ASPEED_SDHCI_TAP_PARAM_INVERT_CLK; +- phase_deg -= 180; +- dev_dbg(dev, +- "Inverting clock to reduce phase correction from %d to %d degrees\n", +- phase_deg + 180, phase_deg); +- } else { +- inverted = 0; +- } ++static u32 aspeed_sdhci_readl(struct sdhci_host *host, int reg) +{ -+ 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); -+ unsigned long hwirq; -+ -+ if (!irq_data || !intc_ic) { -+ pr_err("Invalid irq_data or intc_ic\n"); -+ return; -+ } ++ u32 val = readl(host->ioaddr + reg); + +- prop_delay_ps = ASPEED_SDHCI_MAX_TAP_DELAY_PS / ASPEED_SDHCI_NR_TAPS; +- clk_period_ps = div_u64(PICOSECONDS_PER_SECOND, (u64)rate_hz); +- phase_period_ps = div_u64((u64)phase_deg * clk_period_ps, 360ULL); +- +- tap = div_u64(phase_period_ps, prop_delay_ps); +- if (tap > ASPEED_SDHCI_NR_TAPS) { +- dev_dbg(dev, +- "Requested out of range phase tap %d for %d degrees of phase compensation at %luHz, clamping to tap %d\n", +- tap, phase_deg, rate_hz, ASPEED_SDHCI_NR_TAPS); +- tap = ASPEED_SDHCI_NR_TAPS; +- } ++ if (unlikely(reg == SDHCI_PRESENT_STATE) && ++ (host->mmc->caps2 & MMC_CAP2_CD_ACTIVE_HIGH)) ++ val ^= SDHCI_CARD_PRESENT; + +- return inverted | tap; ++ return val; + } + +-static void +-aspeed_sdhci_phases_to_taps(struct device *dev, unsigned long rate, +- const struct mmc_clk_phase *phases, +- struct aspeed_sdhci_tap_param *taps) ++static void aspeed_sdhci_reset(struct sdhci_host *host, u8 mask) + { +- taps->valid = phases->valid; ++ struct sdhci_pltfm_host *pltfm_priv; ++ struct aspeed_sdhci *aspeed_sdhci; ++ struct aspeed_sdc *aspeed_sdc; ++ u32 save_array[8]; ++ u32 reg_array[] = {SDHCI_DMA_ADDRESS, ++ SDHCI_BLOCK_SIZE, ++ SDHCI_ARGUMENT, ++ SDHCI_HOST_CONTROL, ++ SDHCI_CLOCK_CONTROL, ++ SDHCI_INT_ENABLE, ++ SDHCI_SIGNAL_ENABLE, ++ SDHCI_AUTO_CMD_STATUS}; ++ int i; ++ u16 tran_mode; ++ u32 mmc8_mode; + +- if (!phases->valid) +- return; ++ 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]); + +-static void +-aspeed_sdhci_configure_phase(struct sdhci_host *host, unsigned long rate) +-{ +- 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); + +- 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); + +- if (!sdhci->phase_desc) +- return; ++ for (i = 0; i < ARRAY_SIZE(reg_array); i++) ++ sdhci_writel(host, save_array[i], reg_array[i]); + -+ if (irq_data->hwirq < INTC_IRQ_BASE + 32) { -+ pr_err("Invalid hwirq: %lu\n", irq_data->hwirq); -+ return; ++ sdhci_writew(host, tran_mode, SDHCI_TRANSFER_MODE); ++ writel(mmc8_mode, aspeed_sdc->regs); + +- params = &sdhci->phase_map.phase[host->timing]; +- aspeed_sdhci_phases_to_taps(dev, rate, params, taps); +- aspeed_sdc_set_phase_taps(sdhci->parent, sdhci->phase_desc, taps); +- dev_dbg(dev, +- "Using taps [%d, %d] for [%d, %d] degrees of phase correction at %luHz (%d)\n", +- 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); + } -+ 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); ++ sdhci_reset(host, mask); + } + +-static void aspeed_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) ++static int aspeed_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) + { +- struct sdhci_pltfm_host *pltfm_host; +- unsigned long parent, bus; ++ struct sdhci_pltfm_host *pltfm_priv; + 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; + +- 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); ++ dev = mmc_dev(host->mmc); ++ pltfm_priv = sdhci_priv(host); ++ sdhci = sdhci_pltfm_priv(pltfm_priv); ++ sdc = sdhci->parent; + +- if (clock == 0) +- return; ++ out_phase = readl(sdc->regs + ASPEED_SDC_PHASE) & ASPEED_SDC_S0_PHASE_OUT; + +- 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; + + /* +- * Regarding the AST2600: +- * +- * If (EMMC12C[7:6], EMMC12C[15:8] == 0) then +- * period of SDCLK = period of SDMCLK. +- * +- * If (EMMC12C[7:6], EMMC12C[15:8] != 0) then +- * period of SDCLK = period of SDMCLK * 2 * (EMMC12C[7:6], EMMC[15:8]) +- * +- * If you keep EMMC12C[7:6] = 0 and EMMC12C[15:8] as one-hot, +- * 0x1/0x2/0x4/etc, you will find it is compatible to AST2400 or AST2500 +- * +- * 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; + -+ /* -+ * 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(hwirq), intc_ic->base + INTC_INT_STATUS_REG); -+ raw_spin_unlock(&intc_ic->intc_lock); ++ val = (out_phase | enable_mask | (inverted << ASPEED_SDC_S0_PHASE_IN_SHIFT)); + -+ chained_irq_exit(chip, desc); -+} ++ /* 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); + -+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; ++ if (!mmc_send_tuning(host->mmc, opcode, NULL)) ++ break; ++ } + -+ if (!intc_ic) { -+ pr_err("Invalid intc_ic\n"); -+ return; -+ } ++ /* 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); + -+ chained_irq_enter(chip, desc); ++ if (mmc_send_tuning(host->mmc, opcode, NULL)) ++ break; ++ } + -+ status = readl(intc_ic->base + INTC_INT_STATUS_REG); ++ window = right - left; ++ pr_debug("tuning window[%d][%d~%d] = %d\n", edge, left, right, window); + -+ 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); ++ if (window > oldwindow) { ++ oldwindow = window; ++ center = (((right - 1) + left) / 2) | inverted; ++ } + } + +- 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; + +- sdhci_enable_clk(host, clk); +-} ++ for (edge = 0; edge < 2; edge++) { ++ if (edge == 1) ++ inverted = ASPEED_SDHCI_TAP_PARAM_INVERT_CLK; + +-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)); + +- 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); + +-static void aspeed_sdhci_set_bus_width(struct sdhci_host *host, int width) +-{ +- 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; ++ } + +- 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); + +- /* 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; ++ } + +- /* Set/clear 1 or 4 bit mode */ +- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); +- if (width == MMC_BUS_WIDTH_4) +- ctrl |= SDHCI_CTRL_4BITBUS; +- else +- 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); + +-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; ++ } + } + +- 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); + -+ chained_irq_exit(chip, desc); -+} -+ -+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_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); -+} -+ -+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_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); ++ return mmc_send_tuning(host->mmc, opcode, NULL); +} + -+static struct irq_chip aspeed_intc_chip = { -+ .name = "ASPEED INTC", -+ .irq_mask = aspeed_intc_irq_mask, -+ .irq_unmask = aspeed_intc_irq_unmask, -+}; -+ -+static int aspeed_intc_ic_map_irq_domain(struct irq_domain *domain, unsigned int irq, -+ irq_hw_number_t hwirq) ++static void aspeed_sdhci_voltage_switch(struct sdhci_host *host) +{ -+ irq_set_chip_and_handler(irq, &aspeed_intc_chip, handle_level_irq); -+ irq_set_chip_data(irq, domain->host_data); -+ -+ return 0; -+} -+ -+static const struct irq_domain_ops aspeed_intc_ic_irq_domain_ops = { -+ .map = aspeed_intc_ic_map_irq_domain, -+}; -+ -+static int __init aspeed_intc_ic_of_init(struct device_node *node, -+ struct device_node *parent) -+{ -+ struct aspeed_intc_ic *intc_ic; -+ int ret = 0; -+ int irq, irq_count, i; -+ -+ 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; -+ } -+ 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); -+ if (!intc_ic->irq_domain) { -+ ret = -ENOMEM; -+ goto err_iounmap; -+ } -+ -+ 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; -+ } -+ -+ for (i = 0; i < irq_count; i++) { -+ irq = irq_of_parse_and_map(node, i); -+ if (!irq) { -+ pr_err("Failed to get irq number\n"); -+ 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); -+ } -+ } -+ -+ 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); -+ } -+ iounmap(intc_ic->base); -+err_free_ic: -+ kfree(intc_ic); -+ return ret; -+} -+ -+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 2026-04-08 18:03:48.352704553 +0000 -@@ -1,61 +1,76 @@ - // SPDX-License-Identifier: GPL-2.0-or-later - /* -- * Aspeed AST24XX, AST25XX, and AST26XX SCU Interrupt Controller -+ * Aspeed AST24XX, AST25XX, AST26XX, and AST27XX SCU Interrupt Controller - * Copyright 2019 IBM Corporation - * - * Eddie James - */ ++ mdelay(30); + } - #include -+#include - #include - #include - #include - #include --#include -+#include - #include --#include + static const struct sdhci_ops aspeed_sdhci_ops = { + .read_l = aspeed_sdhci_readl, +- .set_clock = aspeed_sdhci_set_clock, +- .get_max_clock = aspeed_sdhci_get_max_clock, ++ .set_clock = sdhci_set_clock, ++ .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .set_bus_width = aspeed_sdhci_set_bus_width, + .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, +- .reset = sdhci_reset, ++ .voltage_switch = aspeed_sdhci_voltage_switch, ++ .reset = aspeed_sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, ++ .platform_execute_tuning = aspeed_sdhci_execute_tuning, + }; --#define ASPEED_SCU_IC_REG 0x018 --#define ASPEED_SCU_IC_SHIFT 0 --#define ASPEED_SCU_IC_ENABLE GENMASK(15, ASPEED_SCU_IC_SHIFT) --#define ASPEED_SCU_IC_NUM_IRQS 7 - #define ASPEED_SCU_IC_STATUS GENMASK(28, 16) - #define ASPEED_SCU_IC_STATUS_SHIFT 16 -+#define AST2700_SCU_IC_STATUS GENMASK(15, 0) + static const struct sdhci_pltfm_data aspeed_sdhci_pdata = { + .ops = &aspeed_sdhci_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, ++ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, + }; --#define ASPEED_AST2600_SCU_IC0_REG 0x560 --#define ASPEED_AST2600_SCU_IC0_SHIFT 0 --#define ASPEED_AST2600_SCU_IC0_ENABLE \ -- GENMASK(5, ASPEED_AST2600_SCU_IC0_SHIFT) --#define ASPEED_AST2600_SCU_IC0_NUM_IRQS 6 + static inline int aspeed_sdhci_calculate_slot(struct aspeed_sdhci *dev, +@@ -372,12 +362,6 @@ + int slot; + int ret; + +- aspeed_pdata = of_device_get_match_data(&pdev->dev); +- if (!aspeed_pdata) { +- dev_err(&pdev->dev, "Missing platform configuration data\n"); +- return -EINVAL; +- } - --#define ASPEED_AST2600_SCU_IC1_REG 0x570 --#define ASPEED_AST2600_SCU_IC1_SHIFT 4 --#define ASPEED_AST2600_SCU_IC1_ENABLE \ -- GENMASK(5, ASPEED_AST2600_SCU_IC1_SHIFT) --#define ASPEED_AST2600_SCU_IC1_NUM_IRQS 2 -+struct aspeed_scu_ic_variant { -+ const char *compatible; -+ unsigned long irq_enable; -+ unsigned long irq_shift; -+ unsigned int num_irqs; -+ bool split_ier_isr; -+ unsigned long ier; -+ unsigned long isr; -+}; -+ -+#define SCU_VARIANT(_compat, _shift, _enable, _num, _split, _ier, _isr) { \ -+ .compatible = _compat, \ -+ .irq_shift = _shift, \ -+ .irq_enable = _enable, \ -+ .num_irqs = _num, \ -+ .split_ier_isr = _split, \ -+ .ier = _ier, \ -+ .isr = _isr, \ -+} -+ -+static const struct aspeed_scu_ic_variant scu_ic_variants[] __initconst = { -+ SCU_VARIANT("aspeed,ast2400-scu-ic", 0, GENMASK(15, 0), 7, false, 0, 0), -+ SCU_VARIANT("aspeed,ast2500-scu-ic", 0, GENMASK(15, 0), 7, false, 0, 0), -+ SCU_VARIANT("aspeed,ast2600-scu-ic0", 0, GENMASK(5, 0), 6, false, 0, 0), -+ SCU_VARIANT("aspeed,ast2600-scu-ic1", 4, GENMASK(5, 4), 2, false, 0, 0), -+ SCU_VARIANT("aspeed,ast2700-scu-ic0", 0, GENMASK(3, 0), 4, true, 0x00, 0x04), -+ SCU_VARIANT("aspeed,ast2700-scu-ic1", 0, GENMASK(3, 0), 4, true, 0x00, 0x04), -+ SCU_VARIANT("aspeed,ast2700-scu-ic2", 0, GENMASK(3, 0), 4, true, 0x04, 0x00), -+ SCU_VARIANT("aspeed,ast2700-scu-ic3", 0, GENMASK(1, 0), 2, true, 0x04, 0x00), -+}; + host = sdhci_pltfm_init(pdev, &aspeed_sdhci_pdata, sizeof(*dev)); + if (IS_ERR(host)) + return PTR_ERR(host); +@@ -395,14 +379,6 @@ + else if (slot >= 2) + return -EINVAL; - struct aspeed_scu_ic { -- unsigned long irq_enable; -- unsigned long irq_shift; -- unsigned int num_irqs; -- unsigned int reg; -- struct regmap *scu; -- struct irq_domain *irq_domain; -+ unsigned long irq_enable; -+ unsigned long irq_shift; -+ unsigned int num_irqs; -+ void __iomem *base; -+ struct irq_domain *irq_domain; -+ bool split_ier_isr; -+ unsigned long ier; -+ unsigned long isr; - }; +- if (slot < dev->pdata->nr_phase_descs) { +- dev->phase_desc = &dev->pdata->phase_desc[slot]; +- } else { +- dev_info(&pdev->dev, +- "Phase control not supported for slot %d\n", slot); +- dev->phase_desc = NULL; +- } +- + dev->width_mask = !slot ? ASPEED_SDC_S0_MMC8 : ASPEED_SDC_S1_MMC8; --static void aspeed_scu_ic_irq_handler(struct irq_desc *desc) --{ -- unsigned int sts; -- unsigned long bit; -- unsigned long enabled; -- unsigned long max; -- unsigned long status; -+static void aspeed_scu_ic_irq_handler_combined(struct irq_desc *desc) -+{ - struct aspeed_scu_ic *scu_ic = irq_desc_get_handler_data(desc); - struct irq_chip *chip = irq_desc_get_chip(desc); -- unsigned int mask = scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT; -+ unsigned long bit, enabled, max, status; -+ unsigned int sts, mask; + dev_info(&pdev->dev, "Configured for slot %d\n", slot); +@@ -413,11 +389,13 @@ + of_property_read_bool(np, "sd-uhs-sdr104")) { + aspeed_sdc_set_slot_capability(host, dev->parent, ASPEED_SDC_CAP1_1_8V, + true, slot); +- } +- +- if (of_property_read_bool(np, "sd-uhs-sdr104")) { + aspeed_sdc_set_slot_capability(host, dev->parent, ASPEED_SDC_CAP2_SDR104, + true, slot); ++ } else { ++ aspeed_sdc_set_slot_capability(host, dev->parent, ASPEED_SDC_CAP1_1_8V, ++ 0, slot); ++ aspeed_sdc_set_slot_capability(host, dev->parent, ASPEED_SDC_CAP2_SDR104, ++ 0, slot); + } - chained_irq_enter(chip, desc); + pltfm_host->clk = devm_clk_get(&pdev->dev, NULL); +@@ -434,9 +412,6 @@ + if (ret) + goto err_sdhci_add; -+ mask = scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT; - /* - * The SCU IC has just one register to control its operation and read - * status. The interrupt enable bits occupy the lower 16 bits of the -@@ -66,7 +81,7 @@ - * shifting the status down to get the mapping and then back up to - * clear the bit. - */ -- regmap_read(scu_ic->scu, scu_ic->reg, &sts); -+ sts = readl(scu_ic->base); - enabled = sts & scu_ic->irq_enable; - status = (sts >> ASPEED_SCU_IC_STATUS_SHIFT) & enabled; +- if (dev->phase_desc) +- mmc_of_parse_clk_phase(&pdev->dev, &dev->phase_map); +- + ret = sdhci_add_host(host); + if (ret) + goto err_sdhci_add; +@@ -469,45 +444,11 @@ + .clk_div_start = 2, + }; -@@ -76,15 +91,41 @@ - for_each_set_bit_from(bit, &status, max) { - generic_handle_domain_irq(scu_ic->irq_domain, - bit - scu_ic->irq_shift); -+ writel((readl(scu_ic->base) & ~mask) | -+ BIT(bit + ASPEED_SCU_IC_STATUS_SHIFT), -+ scu_ic->base); -+ } -+ -+ chained_irq_exit(chip, desc); -+} -+ -+static void aspeed_scu_ic_irq_handler_split(struct irq_desc *desc) -+{ -+ struct aspeed_scu_ic *scu_ic = irq_desc_get_handler_data(desc); -+ struct irq_chip *chip = irq_desc_get_chip(desc); -+ unsigned long bit, enabled, max, status; -+ unsigned int sts, mask; -+ -+ chained_irq_enter(chip, desc); +-static const struct aspeed_sdhci_phase_desc ast2600_sdhci_phase[] = { +- /* SDHCI/Slot 0 */ +- [0] = { +- .in = { +- .tap_mask = ASPEED_SDC_S0_PHASE_IN, +- .enable_mask = ASPEED_SDC_S0_PHASE_IN_EN, +- .enable_value = 1, +- }, +- .out = { +- .tap_mask = ASPEED_SDC_S0_PHASE_OUT, +- .enable_mask = ASPEED_SDC_S0_PHASE_OUT_EN, +- .enable_value = 3, +- }, +- }, +- /* SDHCI/Slot 1 */ +- [1] = { +- .in = { +- .tap_mask = ASPEED_SDC_S1_PHASE_IN, +- .enable_mask = ASPEED_SDC_S1_PHASE_IN_EN, +- .enable_value = 1, +- }, +- .out = { +- .tap_mask = ASPEED_SDC_S1_PHASE_OUT, +- .enable_mask = ASPEED_SDC_S1_PHASE_OUT_EN, +- .enable_value = 3, +- }, +- }, +-}; +- +-static const struct aspeed_sdhci_pdata ast2600_sdhci_pdata = { +- .clk_div_start = 1, +- .phase_desc = ast2600_sdhci_phase, +- .nr_phase_descs = ARRAY_SIZE(ast2600_sdhci_phase), +-}; +- + static const struct of_device_id aspeed_sdhci_of_match[] = { + { .compatible = "aspeed,ast2400-sdhci", .data = &ast2400_sdhci_pdata, }, +- { .compatible = "aspeed,ast2500-sdhci", .data = &ast2400_sdhci_pdata, }, +- { .compatible = "aspeed,ast2600-sdhci", .data = &ast2600_sdhci_pdata, }, ++ { .compatible = "aspeed,ast2500-sdhci", }, ++ { .compatible = "aspeed,ast2600-sdhci", }, ++ { .compatible = "aspeed,ast2600-emmc", }, + { } + }; + MODULE_DEVICE_TABLE(of, aspeed_sdhci_of_match); +@@ -522,11 +463,22 @@ + .remove_new = aspeed_sdhci_remove, + }; -- regmap_write_bits(scu_ic->scu, scu_ic->reg, mask, -- BIT(bit + ASPEED_SCU_IC_STATUS_SHIFT)); -+ mask = scu_ic->irq_enable; -+ sts = readl(scu_ic->base + scu_ic->isr); -+ enabled = sts & scu_ic->irq_enable; -+ sts = readl(scu_ic->base + scu_ic->isr); -+ status = sts & enabled; ++static const struct of_device_id aspeed_sdc_of_match[] = { ++ { .compatible = "aspeed,ast2400-sd-controller", }, ++ { .compatible = "aspeed,ast2500-sd-controller", }, ++ { .compatible = "aspeed,ast2600-sd-controller", .data = &ast2600_sdc_info}, ++ { } ++}; + -+ bit = scu_ic->irq_shift; -+ max = scu_ic->num_irqs + bit; ++MODULE_DEVICE_TABLE(of, aspeed_sdc_of_match); + -+ for_each_set_bit_from(bit, &status, max) { -+ generic_handle_domain_irq(scu_ic->irq_domain, bit - scu_ic->irq_shift); -+ writel(BIT(bit), scu_ic->base + scu_ic->isr); // clear interrupt - } - - chained_irq_exit(chip, desc); - } + static int aspeed_sdc_probe(struct platform_device *pdev) --static void aspeed_scu_ic_irq_mask(struct irq_data *data) -+static void aspeed_scu_ic_irq_mask_combined(struct irq_data *data) { - struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data); - unsigned int mask = BIT(data->hwirq + scu_ic->irq_shift) | -@@ -95,10 +136,10 @@ - * operation from clearing the status bits, they should be under the - * mask and written with 0. - */ -- regmap_update_bits(scu_ic->scu, scu_ic->reg, mask, 0); -+ writel(readl(scu_ic->base) & ~mask, scu_ic->base); - } + struct device_node *parent, *child; + struct aspeed_sdc *sdc; ++ const struct of_device_id *match = NULL; ++ const struct aspeed_sdc_info *info = NULL; + int ret; --static void aspeed_scu_ic_irq_unmask(struct irq_data *data) -+static void aspeed_scu_ic_irq_unmask_combined(struct irq_data *data) - { - struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data); - unsigned int bit = BIT(data->hwirq + scu_ic->irq_shift); -@@ -110,7 +151,23 @@ - * operation from clearing the status bits, they should be under the - * mask and written with 0. - */ -- regmap_update_bits(scu_ic->scu, scu_ic->reg, mask, bit); -+ writel((readl(scu_ic->base) & ~mask) | bit, scu_ic->base); -+} -+ -+static void aspeed_scu_ic_irq_mask_split(struct irq_data *data) -+{ -+ struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data); + sdc = devm_kzalloc(&pdev->dev, sizeof(*sdc), GFP_KERNEL); +@@ -535,6 +487,23 @@ + + spin_lock_init(&sdc->lock); + ++ match = of_match_device(aspeed_sdc_of_match, &pdev->dev); ++ if (!match) ++ return -ENODEV; + -+ writel(readl(scu_ic->base) & ~BIT(data->hwirq + scu_ic->irq_shift), -+ scu_ic->base + scu_ic->ier); -+} ++ if (match->data) ++ info = match->data; + -+static void aspeed_scu_ic_irq_unmask_split(struct irq_data *data) -+{ -+ struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data); -+ unsigned int bit = BIT(data->hwirq + scu_ic->irq_shift); ++ if (info) { ++ if (info->flag & PROBE_AFTER_ASSET_DEASSERT) { ++ sdc->rst = devm_reset_control_get(&pdev->dev, NULL); ++ if (!IS_ERR(sdc->rst)) { ++ reset_control_assert(sdc->rst); ++ reset_control_deassert(sdc->rst); ++ } ++ } ++ } + -+ writel(readl(scu_ic->base) | bit, scu_ic->base + scu_ic->ier); + sdc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(sdc->clk)) + return PTR_ERR(sdc->clk); +@@ -579,15 +548,6 @@ + clk_disable_unprepare(sdc->clk); } - static int aspeed_scu_ic_irq_set_affinity(struct irq_data *data, -@@ -120,17 +177,29 @@ - return -EINVAL; - } +-static const struct of_device_id aspeed_sdc_of_match[] = { +- { .compatible = "aspeed,ast2400-sd-controller", }, +- { .compatible = "aspeed,ast2500-sd-controller", }, +- { .compatible = "aspeed,ast2600-sd-controller", }, +- { } +-}; +- +-MODULE_DEVICE_TABLE(of, aspeed_sdc_of_match); +- + 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 @@ --static struct irq_chip aspeed_scu_ic_chip = { -- .name = "aspeed-scu-ic", -- .irq_mask = aspeed_scu_ic_irq_mask, -- .irq_unmask = aspeed_scu_ic_irq_unmask, -- .irq_set_affinity = aspeed_scu_ic_irq_set_affinity, -+static struct irq_chip aspeed_scu_ic_chip_combined = { -+ .name = "aspeed-scu-ic", -+ .irq_mask = aspeed_scu_ic_irq_mask_combined, -+ .irq_unmask = aspeed_scu_ic_irq_unmask_combined, -+ .irq_set_affinity = aspeed_scu_ic_irq_set_affinity, -+}; -+ -+static struct irq_chip aspeed_scu_ic_chip_split = { -+ .name = "ast2700-scu-ic", -+ .irq_mask = aspeed_scu_ic_irq_mask_split, -+ .irq_unmask = aspeed_scu_ic_irq_unmask_split, -+ .irq_set_affinity = aspeed_scu_ic_irq_set_affinity, - }; + if CAN_NETLINK - static int aspeed_scu_ic_map(struct irq_domain *domain, unsigned int irq, - irq_hw_number_t hwirq) - { -- irq_set_chip_and_handler(irq, &aspeed_scu_ic_chip, handle_level_irq); -+ struct aspeed_scu_ic *scu_ic = domain->host_data; ++config CAN_ASPEED ++ tristate "ASPEED CAN" ++ depends on ARM64 || COMPILE_TEST ++ help ++ ASPEED CAN driver. + -+ if (scu_ic->split_ier_isr) -+ irq_set_chip_and_handler(irq, &aspeed_scu_ic_chip_split, handle_level_irq); -+ else -+ irq_set_chip_and_handler(irq, &aspeed_scu_ic_chip_combined, handle_level_irq); - irq_set_chip_data(irq, domain->host_data); - - return 0; -@@ -146,18 +215,19 @@ - int irq; - int rc = 0; - -- if (!node->parent) { -- rc = -ENODEV; -+ scu_ic->base = of_iomap(node, 0); -+ if (IS_ERR(scu_ic->base)) { -+ rc = PTR_ERR(scu_ic->base); - goto err; - } - -- scu_ic->scu = syscon_node_to_regmap(node->parent); -- if (IS_ERR(scu_ic->scu)) { -- rc = PTR_ERR(scu_ic->scu); -- goto err; -+ if (scu_ic->split_ier_isr) { -+ writel(AST2700_SCU_IC_STATUS, scu_ic->base + scu_ic->isr); -+ writel(0, scu_ic->base + scu_ic->ier); -+ } else { -+ writel(ASPEED_SCU_IC_STATUS, scu_ic->base); -+ writel(0, scu_ic->base); - } -- regmap_write_bits(scu_ic->scu, scu_ic->reg, ASPEED_SCU_IC_STATUS, ASPEED_SCU_IC_STATUS); -- regmap_write_bits(scu_ic->scu, scu_ic->reg, ASPEED_SCU_IC_ENABLE, 0); - - irq = irq_of_parse_and_map(node, 0); - if (!irq) { -@@ -166,14 +236,15 @@ - } + 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/ - scu_ic->irq_domain = irq_domain_add_linear(node, scu_ic->num_irqs, -- &aspeed_scu_ic_domain_ops, -- scu_ic); -+ &aspeed_scu_ic_domain_ops, scu_ic); - if (!scu_ic->irq_domain) { - rc = -ENOMEM; - goto err; - } - -- irq_set_chained_handler_and_data(irq, aspeed_scu_ic_irq_handler, -+ irq_set_chained_handler_and_data(irq, scu_ic->split_ier_isr ? -+ aspeed_scu_ic_irq_handler_split : -+ aspeed_scu_ic_irq_handler_combined, - scu_ic); - - return 0; -@@ -184,57 +255,45 @@ - return rc; - } - --static int __init aspeed_scu_ic_of_init(struct device_node *node, -- struct device_node *parent) -+static const struct aspeed_scu_ic_variant * -+aspeed_scu_ic_find_variant(struct device_node *np) - { -- struct aspeed_scu_ic *scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL); -- -- if (!scu_ic) -- return -ENOMEM; -- -- scu_ic->irq_enable = ASPEED_SCU_IC_ENABLE; -- scu_ic->irq_shift = ASPEED_SCU_IC_SHIFT; -- scu_ic->num_irqs = ASPEED_SCU_IC_NUM_IRQS; -- scu_ic->reg = ASPEED_SCU_IC_REG; -+ for (int i = 0; i < ARRAY_SIZE(scu_ic_variants); i++) { -+ if (of_device_is_compatible(np, scu_ic_variants[i].compatible)) -+ return &scu_ic_variants[i]; -+ } - -- return aspeed_scu_ic_of_init_common(scu_ic, node); -+ return NULL; - } - --static int __init aspeed_ast2600_scu_ic0_of_init(struct device_node *node, -- struct device_node *parent) -+static int __init aspeed_scu_ic_of_init(struct device_node *node, struct device_node *parent) - { -- struct aspeed_scu_ic *scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL); -- -- if (!scu_ic) -- return -ENOMEM; -- -- scu_ic->irq_enable = ASPEED_AST2600_SCU_IC0_ENABLE; -- scu_ic->irq_shift = ASPEED_AST2600_SCU_IC0_SHIFT; -- scu_ic->num_irqs = ASPEED_AST2600_SCU_IC0_NUM_IRQS; -- scu_ic->reg = ASPEED_AST2600_SCU_IC0_REG; -- -- return aspeed_scu_ic_of_init_common(scu_ic, node); --} -+ const struct aspeed_scu_ic_variant *variant; -+ struct aspeed_scu_ic *scu_ic; - --static int __init aspeed_ast2600_scu_ic1_of_init(struct device_node *node, -- struct device_node *parent) --{ -- struct aspeed_scu_ic *scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL); -+ variant = aspeed_scu_ic_find_variant(node); -+ if (!variant) -+ return -ENODEV; - -+ scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL); - if (!scu_ic) - return -ENOMEM; - -- scu_ic->irq_enable = ASPEED_AST2600_SCU_IC1_ENABLE; -- scu_ic->irq_shift = ASPEED_AST2600_SCU_IC1_SHIFT; -- scu_ic->num_irqs = ASPEED_AST2600_SCU_IC1_NUM_IRQS; -- scu_ic->reg = ASPEED_AST2600_SCU_IC1_REG; -+ scu_ic->irq_enable = variant->irq_enable; -+ scu_ic->irq_shift = variant->irq_shift; -+ scu_ic->num_irqs = variant->num_irqs; -+ scu_ic->split_ier_isr = variant->split_ier_isr; -+ scu_ic->ier = variant->ier; -+ scu_ic->isr = variant->isr; - - return aspeed_scu_ic_of_init_common(scu_ic, node); - } - - IRQCHIP_DECLARE(ast2400_scu_ic, "aspeed,ast2400-scu-ic", aspeed_scu_ic_of_init); - IRQCHIP_DECLARE(ast2500_scu_ic, "aspeed,ast2500-scu-ic", aspeed_scu_ic_of_init); --IRQCHIP_DECLARE(ast2600_scu_ic0, "aspeed,ast2600-scu-ic0", -- aspeed_ast2600_scu_ic0_of_init); --IRQCHIP_DECLARE(ast2600_scu_ic1, "aspeed,ast2600-scu-ic1", -- aspeed_ast2600_scu_ic1_of_init); -+IRQCHIP_DECLARE(ast2600_scu_ic0, "aspeed,ast2600-scu-ic0", aspeed_scu_ic_of_init); -+IRQCHIP_DECLARE(ast2600_scu_ic1, "aspeed,ast2600-scu-ic1", aspeed_scu_ic_of_init); -+IRQCHIP_DECLARE(ast2700_scu_ic0, "aspeed,ast2700-scu-ic0", aspeed_scu_ic_of_init); -+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/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-04-08 18:03:48.199707348 +0000 -@@ -0,0 +1,509 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Aspeed Interrupt Controller. ++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 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ASPEED CAN device driver + * -+ * Copyright (C) 2023 ASPEED Technology Inc. ++ * Copyright (C) 2023 ASPEED 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 ++#include ++#include ++#include + -+#include ++#define DRIVER_NAME "aspeed_can" + -+#define INT_NUM 480 -+#define SWINT_NUM 16 -+#define INTM_NUM 50 ++#define CAN_AC_SEG (0x0004) /* classic can seg */ ++#define CAN_FD_SEG (0x0008) /* can fd seg */ ++#define CAN_BITITME (0x0010) /* prescaler */ ++#define CAN_INTF (0x0014) /* can interrupt flag */ ++#define CAN_INTE (0x0018) /* can interrupt enabled */ ++#define CAN_TSTAT (0x001c) /* can transmit status */ + -+#define SWINT_BASE (INT_NUM) -+#define INTM_BASE (INT_NUM + SWINT_NUM) -+#define INT0_NUM (INT_NUM + SWINT_NUM + INTM_NUM) ++#define CAN_CTRL (0x0028) ++#define CAN_ERR_STAT (0x002c) /* err ctrl and rx/tx err status */ + -+#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 CAN_RBUF (0x0070) /* receive buffer registers 0x070-0x88b(*/ ++#define CAN_TBUF (0x0890) /* transmit buffer registers 0x890-0x10ab */ + -+#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 ++#define CAN_RBUF_ID (CAN_RBUF + 0x0000) ++#define CAN_RBUF_CTL (CAN_RBUF + 0x0004) ++#define CAN_RBUF_TYPE (CAN_RBUF + 0x0008) ++#define CAN_RBUF_ACF (CAN_RBUF + 0x000C) ++#define CAN_RBUF_DATA (CAN_RBUF + 0x0010) + -+struct intc0_pin_region { -+ u32 int_base; -+ u32 gic_base; -+ u32 cnt; -+}; ++#define CAN_TBUF_ID (CAN_TBUF + 0x0000) ++#define CAN_TBUF_CTL (CAN_TBUF + 0x0004) ++#define CAN_TBUF_TYPE (CAN_TBUF + 0x0008) ++#define CAN_TBUF_ACF (CAN_TBUF + 0x000C) ++#define CAN_TBUF_DATA (CAN_TBUF + 0x0010) + -+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; -+}; ++#define CAN_MODE_CONFIG (0x1100) + -+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; ++#define CAN_TBUF_MIRROR (0x1190) ++#define CAN_TBUF_READ_ID (CAN_TBUF_MIRROR + 0x0000) ++#define CAN_TBUF_READ_CTL (CAN_TBUF_MIRROR + 0x0004) ++#define CAN_TBUF_READ_TYPE (CAN_TBUF_MIRROR + 0x0008) ++#define CAN_TBUF_READ_ACF (CAN_TBUF_MIRROR + 0x000C) ++#define CAN_TBUF_READ_DATA (CAN_TBUF_MIRROR + 0x0010) + -+ 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); -+} ++/* CAN_AC_SEG(0x0004) bit description */ ++#define CAN_TIMING_AC_SEG1_MASK GENMASK(8, 0) ++#define CAN_TIMING_AC_SEG2_MASK GENMASK(22, 16) ++#define CAN_TIMING_AC_SJW_MASK GENMASK(30, 24) + -+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; ++#define CAN_TIMING_AC_SEG1_BITOFF 0 ++#define CAN_TIMING_AC_SEG2_BITOFF 16 ++#define CAN_TIMING_AC_SJW_BITOFF 24 + -+ 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); -+} ++/* CAN_FD_SEG(0x0008) bit description */ ++#define CAN_TIMING_FD_SEG1_MASK GENMASK(7, 0) ++#define CAN_TIMING_FD_SEG2_MASK GENMASK(22, 16) ++#define CAN_TIMING_FD_SJW_MASK GENMASK(30, 24) + -+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; ++#define CAN_TIMING_FD_SEG1_BITOFF 0 ++#define CAN_TIMING_FD_SEG2_BITOFF 16 ++#define CAN_TIMING_FD_SJW_BITOFF 24 + -+ writel(BIT(bit), intc_ic->base + INTC0_SWINT_ISR); -+ irq_chip_eoi_parent(data); -+} ++/* CAN_BITTIME(0x0010) bit description */ ++#define CAN_TIMING_PRESC_MASK GENMASK(4, 0) ++#define CAN_TIMING_PRESC_BITOFF 0 ++#define CAN_TIMING_FD_SSPOFF_MASK GENMASK(15, 8) ++#define CAN_TIMING_FD_SSPOFF_BITOFF 8 + -+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, -+}; ++/* CAN_INTF(0x0014) bit description */ ++#define CAN_INT_EIF_BIT BIT(1) /* error interrupt flag */ ++#define CAN_INT_TSIF_BIT BIT(2) /* transmission secondary interrupt flag */ ++#define CAN_INT_TPIF_BIT BIT(3) /* transmission primary interrupt flag */ ++#define CAN_INT_RAFIF_BIT BIT(4) /* RB almost full interrupt flag */ ++#define CAN_INT_RFIF_BIT BIT(5) /* RB full interrupt flag */ ++#define CAN_INT_ROIF_BIT BIT(6) /* RB overflow interrupt flag */ ++#define CAN_INT_RIF_BIT BIT(7) /* receive interrupt flag */ ++#define CAN_INT_BEIF_BIT BIT(8) /* bus error interrupt flag */ ++#define CAN_INT_ALIF_BIT BIT(9) /* arbitration loss interrupt flag */ ++#define CAN_INT_EPIF_BIT BIT(10) /* error passive interrupt flag */ ++#define CAN_EPASS_BIT BIT(30) /* check if device is error passive */ ++#define CAN_INT_EWARN_BIT BIT(31) /* error Warning limit reached */ + -+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; ++/* CAN_INTE(0x0018) bit description */ ++#define CAN_INT_EIE_BIT BIT(1) /* error interrupt enable */ ++#define CAN_INT_TSIE_BIT BIT(2) /* transmission secondary interrupt enable */ ++#define CAN_INT_TPIE_BIT BIT(3) /* transmission secondary interrupt enable */ ++#define CAN_INT_RAFIE_BIT BIT(4) /* RB almost full interrupt enable */ ++#define CAN_INT_RFIE_BIT BIT(5) /* RB full interrupt enable */ ++#define CAN_INT_ROIE_BIT BIT(6) /* RB overflow interrupt enable */ ++#define CAN_INT_RIE_BIT BIT(7) /* receive interrupt enable */ ++#define CAN_INT_BEIE_BIT BIT(8) /* bus error interrupt enable */ ++#define CAN_INT_ALIE_BIT BIT(9) /* arbitration loss interrupt enable */ ++#define CAN_INT_EPIE_BIT BIT(10) /* error passive interrupt enable */ + -+ 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); -+} ++/* CAN_TSTAT(0x001C) bit description */ ++#define CAN_TSTAT1_MASK GENMASK(10, 8) ++#define CAN_TSTAT1_BITOFF 8 ++#define CAN_TSTAT2_HANDLE_MASK GENMASK(23, 16) ++#define CAN_TSTAT2_HANDLE_BITOFF 16 ++#define CAN_TSTAT2_MASK GENMASK(26, 24) ++#define CAN_TSTAT2_BITOFF 24 + -+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; ++/* CAN_CTRL(0x0028) bit description */ ++#define CAN_CTRL_BUSOFF_BIT BIT(0) ++#define CAN_CTRL_LBMIMOD_BIT BIT(5) /* set loop back mode, internal */ ++#define CAN_CTRL_LBMEMOD_BIT BIT(6) /* set loop back mode, external */ ++#define CAN_CTRL_RST_BIT BIT(7) /* set reset bit */ ++#define CAN_CTRL_TSALL_BIT BIT(9) /* transmit secondary all frame */ ++#define CAN_CTRL_TSONE_BIT BIT(10) /* transmit secondary one frame */ ++#define CAN_CTRL_TPE_BIT BIT(12) /* transmit primary enable */ ++#define CAN_CTRL_STBY_BIT BIT(13) /* transceiver standby */ ++#define CAN_CTRL_TBSEL_BIT BIT(15) /* transmit buffer select */ ++#define CAN_CTRL_TSSTAT_MASK GENMASK(17, 16) /* Transmission secondary status bits */ ++#define CAN_CTRL_TSFF_BIT BIT(18) /* transmit secondary buffer full flag */ ++#define CAN_CTRL_TTBM_BIT BIT(20) /* set TTTBM as 1->full TTCAN mode */ ++#define CAN_CTRL_TSMODE_BIT BIT(21) /* set TSMODE as 1->FIFO mode */ ++#define CAN_CTRL_TSNEXT_BIT BIT(22) /* transmit buffer secondary NEXT */ ++#define CAN_CTRL_RSTAT_NOT_EMPTY_MASKT GENMASK(25, 24) ++#define CAN_CTRL_RREL_BIT BIT(28) /* receive buffer release */ ++#define CAN_CTRL_SACK_BIT BIT(31) /* self-ack mode */ + -+ 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); -+} ++#define STB_IS_EMPTY 0x0 + -+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; ++/* CAN_ERR(0x002c) bit description */ ++#define CAN_ERR_EWL_MASK GENMASK(3, 0) /* programmable error warning limit */ ++#define CAN_ERR_EWL_BITOFF 0 ++#define CAN_ERR_AFWL_MASK GENMASK(7, 4) /* receive buffer almost full warning limit */ ++#define CAN_ERR_AFWL_BITOFF 4 ++#define CAN_ERR_ALC_MASK GENMASK(12, 8) /* arbitration lost capture */ ++#define CAN_ERR_ALC_BITOFF 8 ++#define CAN_ERR_KOER_MASK GENMASK(15, 13) /* kind of error */ ++#define CAN_ERR_KOER_BITOFF 13 ++#define CAN_ERR_RECNT_MASK GENMASK(23, 16) /* receive error count */ ++#define CAN_ERR_RECNT_BITOFF 16 ++#define CAN_ERR_TECNT_MASK GENMASK(31, 24) /* transmit error count */ ++#define CAN_ERR_TECNT_BITOFF 24 + -+ /* -+ * 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); ++/* CAN BUF bit description*/ ++#define CAN_BUF_ID_BFF_MASK GENMASK(28, 18) /* frame identifier */ ++#define CAN_BUF_ID_BFF_BITOFF 18 ++#define CAN_BUF_ID_EFF_MASK GENMASK(28, 0) /* identifier extension */ ++#define CAN_BUF_ID_EFF_BITOFF 0 ++#define CAN_BUF_DLC_MASK GENMASK(10, 0) /* data length code */ ++#define CAN_BUF_IDE_BIT BIT(16) /* identifier extension */ ++#define CAN_BUF_FDF_BIT BIT(17) /* CAN FD frame format */ ++#define CAN_BUF_BRS_BIT BIT(18) /* CAN FD bit rate switch enable */ ++#define CAN_BUF_RMF_BIT BIT(20) /* remot frame */ ++#define CAN_BUF_HANDLE_BITOFF 24 + -+ irq_chip_eoi_parent(data); -+} ++#define KOER_BIT_ERROR_MASK (BIT(0)) ++#define KOER_FORM_ERROR_MASK (BIT(1)) ++#define KOER_STUFF_ERROR_MASK (BIT(1) | BIT(0)) ++#define KOER_ACK_ERROR_MASK (BIT(2)) ++#define KOER_CRC_ERROR_MASK (BIT(2) | BIT(0)) ++#define KOER_OTH_ERROR_MASK (BIT(2) | BIT(1)) ++ ++#define STAT_AFWL 0x04 ++#define STAT_EWL 0x0b ++ ++#define STB_IDX_RING_SZ 3 ++ ++#define PTB_MODE 0x01 ++#define STB_MODE 0x02 ++ ++#define STB_TX_MODE_ALL 0x01 /* secondary tx buffer mode */ ++#define STB_TX_MODE_ONE 0x02 /* secondary tx buffer mode */ ++#define STB_POLICY_FIFO 0x10 /* secondary tx buffer fifo mode */ ++#define STB_POLICY_PRIO 0x20 /* secondary tx buffer prioity mode */ ++ ++#define STB_INVALID_HANDLE_VAL 0xffffffff ++#define STB_INVALID_SKB_IDX 0xffffffff ++ ++/* SW flag */ ++#define ASPEED_CAN_INTERNEL_LOOPBACK 0x00000001 ++ ++struct can_stb_ring_obj { ++ u32 idx; ++ u32 skb_idx; ++ u32 handle; ++ struct can_stb_ring_obj *next; ++}; + -+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, ++struct aspeed_can_priv { ++ /* Fix the location of "struct can_priv can" ++ * in this struct. ++ */ ++ struct can_priv can; ++ void __iomem *reg_base; ++ struct device *dev; ++ /* Lock for synchronizing TX interrupt handling */ ++ spinlock_t tx_lock; ++ struct can_stb_ring_obj *stb_ring; ++ struct can_stb_ring_obj *head_ptr; ++ struct can_stb_ring_obj *tail_ptr; ++ u32 tx_max; ++ struct napi_struct napi; ++ struct clk *clk; ++ struct reset_control *reset; ++ u32 tb_mode; ++ u32 stb_mode_policy; ++ u32 frame_handle; ++ u32 flag; ++}; + ++static const struct can_bittiming_const aspeed_can_bittiming_const = { ++ .name = DRIVER_NAME, ++ .tseg1_min = 2, ++ .tseg1_max = 513, ++ .tseg2_min = 1, ++ .tseg2_max = 128, ++ .sjw_max = 128, ++ .brp_min = 1, ++ .brp_max = 128, ++ .brp_inc = 1, +}; + -+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 const struct can_bittiming_const aspeed_canfd_bittiming_const = { ++ .name = DRIVER_NAME, ++ .tseg1_min = 2, ++ .tseg1_max = 257, ++ .tseg2_min = 1, ++ .tseg2_max = 128, ++ .sjw_max = 128, ++ .brp_min = 1, ++ .brp_max = 128, ++ .brp_inc = 1, +}; + -+static int aspeed_intc_ic0_map_irq_domain(struct irq_domain *domain, unsigned int irq, -+ irq_hw_number_t hwirq) ++inline void aspeed_can_set_bit(struct aspeed_can_priv *priv, ++ u32 reg_off, u32 bit) +{ -+ 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; ++ u32 reg_val; + -+ irq_set_chip_data(irq, domain->host_data); -+ return 0; ++ reg_val = readl(priv->reg_base + reg_off); ++ reg_val |= bit; ++ writel(reg_val, priv->reg_base + reg_off); +} + -+static int aspeed_intc0_irq_domain_translate(struct irq_domain *domain, -+ struct irq_fwspec *fwspec, -+ unsigned long *hwirq, -+ unsigned int *type) ++inline void aspeed_can_clr_bit(struct aspeed_can_priv *priv, ++ u32 reg_off, u32 bit) +{ -+ if (fwspec->param_count != 1) -+ return -EINVAL; ++ u32 reg_val; + -+ *hwirq = fwspec->param[0]; -+ *type = IRQ_TYPE_NONE; -+ return 0; ++ reg_val = readl(priv->reg_base + reg_off); ++ reg_val &= ~(bit); ++ writel(reg_val, priv->reg_base + reg_off); +} + -+static int get_parent_hwirq(struct aspeed_intc_ic *intc_ic, -+ u32 local_hwirq, -+ irq_hw_number_t *parent_hwirq) ++inline void aspeed_can_clr_irq_bits(struct aspeed_can_priv *priv, ++ u32 reg_off, u32 bits) +{ -+ int i; ++ writel(bits, priv->reg_base + reg_off); ++} + -+ 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; ++static bool aspeed_can_check_reset_mode(struct net_device *ndev) ++{ ++ struct aspeed_can_priv *priv = netdev_priv(ndev); + -+ 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; -+ } -+ } ++ if (!(readl(priv->reg_base + CAN_CTRL) & CAN_CTRL_RST_BIT)) ++ return false; + -+ return -EINVAL; ++ return true; +} + -+static int aspeed_intc0_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, -+ unsigned int nr_irqs, void *data) ++static void aspeed_can_stb_ring_obj_init(struct net_device *ndev) +{ -+ 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; ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ int i; + -+ ret = aspeed_intc0_irq_domain_translate(domain, fwspec, &hwirq, &type); -+ if (ret) -+ return ret; ++ for (i = 0; i < STB_IDX_RING_SZ; i++) { ++ priv->stb_ring[i].idx = i + 1; ++ priv->stb_ring[i].skb_idx = i + 1; ++ priv->stb_ring[i].handle = STB_INVALID_HANDLE_VAL; + -+ if (hwirq >= GIC_P2P_SPI_END && hwirq < INT_NUM) -+ return -EINVAL; ++ if (i == STB_IDX_RING_SZ - 1) { ++ priv->stb_ring[i].next = &priv->stb_ring[0]; ++ } else { ++ priv->stb_ring[i].next = ++ &priv->stb_ring[i + 1]; ++ } ++ } + -+ if (hwirq < SWINT_BASE) -+ chip = &linear_intr_irq_chip; -+ else if (hwirq < INTM_BASE) -+ chip = &aspeed_swint_chip; -+ else -+ chip = &aspeed_intm_chip; ++ priv->head_ptr = &priv->stb_ring[0]; ++ priv->tail_ptr = &priv->stb_ring[0]; ++} + -+ ret = get_parent_hwirq(intc_ic, (u32)hwirq, &parent_hwirq); -+ if (ret) -+ return irq_domain_disconnect_hierarchy(domain->parent, virq); ++static u32 aspeed_can_get_skb_idx(struct net_device *ndev, ++ u32 handle) ++{ ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ struct can_stb_ring_obj *tmp_ptr = priv->tail_ptr; + -+ 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; ++ if (tmp_ptr->handle == handle) ++ return tmp_ptr->skb_idx; + -+ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_fwspec); -+ if (ret) -+ return ret; ++ tmp_ptr = priv->tail_ptr->next; + -+ 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; ++ while (tmp_ptr != priv->head_ptr) { ++ if (tmp_ptr->handle == handle) ++ return tmp_ptr->skb_idx; ++ tmp_ptr = tmp_ptr->next; + } + -+ return 0; ++ return STB_INVALID_SKB_IDX; +} + -+static int aspeed_intc0_irq_domain_activate(struct irq_domain *domain, -+ struct irq_data *data, bool reserve) ++static int aspeed_can_drop_ring_obj(struct net_device *ndev, ++ u32 handle) +{ -+ struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ struct can_stb_ring_obj *tmp_ptr = priv->tail_ptr; ++ u32 tmp_skb_idx; ++ ++ if (tmp_ptr->handle == handle) { ++ /* keep original skb idx */ ++ tmp_ptr->handle = STB_INVALID_HANDLE_VAL; ++ priv->tail_ptr = priv->tail_ptr->next; ++ return 0; ++ } + -+ if (data->hwirq < GIC_P2P_SPI_END) { -+ int bank = data->hwirq / 32; -+ int bit = data->hwirq % 32; -+ u32 mask = BIT(bit); ++ tmp_ptr = priv->tail_ptr->next; + -+ 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; ++ while (tmp_ptr != priv->head_ptr) { ++ if (tmp_ptr->handle == handle) { ++ tmp_skb_idx = tmp_ptr->skb_idx; ++ tmp_ptr->handle = priv->tail_ptr->handle; ++ tmp_ptr->skb_idx = priv->tail_ptr->skb_idx; + -+ if (readl(sel) & mask) { -+ writel(readl(sel) & ~mask, sel); -+ if (readl(sel) & mask) -+ return -EACCES; -+ } ++ priv->tail_ptr->skb_idx = tmp_skb_idx; ++ priv->tail_ptr->handle = STB_INVALID_HANDLE_VAL; ++ priv->tail_ptr = priv->tail_ptr->next; ++ return 0; + } -+ } else if (data->hwirq < INT_NUM) { -+ return -EINVAL; -+ } else if (data->hwirq < INT0_NUM) { -+ return 0; -+ } else { -+ return -EINVAL; ++ ++ tmp_ptr = tmp_ptr->next; + } + -+ return 0; ++ return -1; +} + -+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) ++static u32 aspeed_can_get_frame_num(struct net_device *ndev) +{ -+ struct intc0_pin_region *pin_region; -+ int region_cnt = 0; -+ int i, n, ret; ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ struct can_stb_ring_obj *tmp_ptr = priv->tail_ptr; ++ u32 len = 0; + -+ if (!of_device_is_compatible(parent_node, "arm,gic-v3")) -+ return -ENOENT; ++ if (tmp_ptr == priv->head_ptr) ++ return STB_IDX_RING_SZ; + -+ n = of_property_count_elems_of_size(node, "aspeed,interrupt-ranges", sizeof(u32)); -+ if (n <= 0 || n % 6) -+ return -EINVAL; ++ while (tmp_ptr != priv->head_ptr) { ++ len++; ++ tmp_ptr = tmp_ptr->next; ++ } + -+ /* -+ * 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; ++ return len; ++} + -+ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", -+ i * 6 + 2, &parent_handle); -+ if (ret) -+ return ret; ++static int aspeed_can_set_reset_mode(struct net_device *ndev) ++{ ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ unsigned long timeout; + -+ target = of_find_node_by_phandle(parent_handle); -+ if (!target) -+ continue; ++ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_RST_BIT); + -+ if (target != parent_node) { -+ of_node_put(target); -+ continue; ++ timeout = jiffies + (1 * HZ); ++ while (!aspeed_can_check_reset_mode(ndev)) { ++ if (time_after(jiffies, timeout)) { ++ netdev_warn(ndev, "timed out for config mode\n"); ++ return -ETIMEDOUT; + } + -+ 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++; ++ usleep_range(500, 10000); + } + -+ if (!region_cnt) -+ return -EINVAL; ++ aspeed_can_stb_ring_obj_init(ndev); + -+ 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; ++ return 0; ++} + -+ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", -+ i * 6 + 2, &parent_handle); -+ if (ret) -+ return ret; ++static int aspeed_can_exit_reset_mode(struct net_device *ndev) ++{ ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ unsigned long timeout; + -+ target = of_find_node_by_phandle(parent_handle); -+ if (!target) -+ continue; ++ aspeed_can_clr_bit(priv, CAN_CTRL, CAN_CTRL_RST_BIT); + -+ if (target != parent_node) { -+ of_node_put(target); -+ continue; ++ timeout = jiffies + (1 * HZ); ++ while (aspeed_can_check_reset_mode(ndev)) { ++ if (time_after(jiffies, timeout)) { ++ netdev_warn(ndev, "timed out for config mode\n"); ++ return -ETIMEDOUT; + } + -+ 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; ++ usleep_range(500, 10000); ++ } + -+ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", -+ i * 6 + 3, &gic_type); -+ if (ret) -+ goto out_put; ++ return 0; ++} + -+ if (gic_type != GIC_SPI) -+ goto out_put; ++static void aspeed_can_err_init(struct net_device *ndev) ++{ ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ u32 reg_val; + -+ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", -+ i * 6 + 4, -+ &pin_region[region_cnt].gic_base); -+ if (ret) -+ goto out_put; ++ reg_val = (STAT_AFWL << CAN_ERR_AFWL_BITOFF) & CAN_ERR_AFWL_MASK; ++ reg_val |= (STAT_EWL << CAN_ERR_EWL_BITOFF) & CAN_ERR_EWL_MASK; + -+ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", -+ i * 6 + 5, &gic_flags); -+ if (ret) -+ goto out_put; ++ writel(reg_val, priv->reg_base + CAN_ERR_STAT); ++} + -+ if (gic_flags != IRQ_TYPE_LEVEL_HIGH) -+ goto out_put; ++static void aspeed_can_interrupt_conf(struct net_device *ndev) ++{ ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ u32 inte; + -+ region_cnt++; -+out_put: -+ of_node_put(target); -+ if (ret) -+ return ret; -+ } ++ inte = CAN_INT_EIE_BIT | CAN_INT_TSIE_BIT | CAN_INT_TPIE_BIT | ++ CAN_INT_RAFIE_BIT | CAN_INT_RFIE_BIT | CAN_INT_ROIE_BIT | ++ CAN_INT_RIE_BIT | CAN_INT_BEIE_BIT | CAN_INT_ALIE_BIT | ++ CAN_INT_EPIE_BIT; + -+ return 0; ++ writel(inte, priv->reg_base + CAN_INTE); +} + -+static void aspeed_intc0_disable_swint(struct aspeed_intc_ic *intc_ic) ++static void aspeed_can_tb_mode_conf(struct net_device *ndev) +{ -+ writel(0, intc_ic->base + INTC0_SWINT_IER); ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ ++ if (priv->tb_mode == STB_MODE) ++ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_TBSEL_BIT); ++ else ++ aspeed_can_clr_bit(priv, CAN_CTRL, CAN_CTRL_TBSEL_BIT); +} + -+static void aspeed_intc0_disable_intbank(struct aspeed_intc_ic *intc_ic) ++static void aspeed_can_sack_conf(struct net_device *ndev, bool enable) +{ -+ int i, j; ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ ++ if (enable) ++ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_SACK_BIT); ++ else ++ aspeed_can_clr_bit(priv, CAN_CTRL, CAN_CTRL_SACK_BIT); ++} + -+ 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); ++static void aspeed_can_loopback_ext_conf(struct net_device *ndev, bool enable) ++{ ++ struct aspeed_can_priv *priv = netdev_priv(ndev); + -+ writel(0, intc_ic->base + base); -+ } -+ } ++ if (enable) ++ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_LBMEMOD_BIT); ++ else ++ aspeed_can_clr_bit(priv, CAN_CTRL, CAN_CTRL_LBMEMOD_BIT); +} + -+static void aspeed_intc0_disable_intm(struct aspeed_intc_ic *intc_ic) ++static void aspeed_can_loopback_int_conf(struct net_device *ndev, bool enable) +{ -+ int i; ++ struct aspeed_can_priv *priv = netdev_priv(ndev); + -+ for (i = 0; i < INTC0_IMTM_BANK_NUM; i++) -+ writel(0, intc_ic->base + INTC0_IMTMX_IER + (0x10 * i)); ++ if (enable) ++ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_LBMIMOD_BIT); ++ else ++ aspeed_can_clr_bit(priv, CAN_CTRL, CAN_CTRL_LBMIMOD_BIT); +} + -+static int aspeed_intc0_ic_of_init(struct device_node *node, struct device_node *parent) ++static void aspeed_can_fd_init(struct net_device *ndev) +{ -+ struct irq_domain *parent_domain; -+ struct aspeed_intc_ic *intc_ic; -+ int ret; ++ struct aspeed_can_priv *priv = netdev_priv(ndev); + -+ if (!parent) { -+ pr_err("missing parent interrupt node\n"); -+ return -ENODEV; -+ } ++ aspeed_can_set_bit(priv, CAN_MODE_CONFIG, BIT(0)); ++} + -+ intc_ic = kzalloc(sizeof(*intc_ic), GFP_KERNEL); -+ if (!intc_ic) -+ return -ENOMEM; ++static void aspeed_can_reg_dump(struct net_device *ndev) ++{ ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ u32 reg_val; ++ u32 i; + -+ intc_ic->base = of_iomap(node, 0); -+ if (!intc_ic->base) { -+ ret = -ENOMEM; -+ goto err_free_ic; -+ } ++ reg_val = readl(priv->reg_base + CAN_AC_SEG); ++ netdev_info(ndev, "(REG004) CAN_AC_SEG = 0x%08x\n", reg_val); ++ netdev_info(ndev, " ac_seg1 (8:0): 0x%02x\n", ++ (u32)((reg_val & CAN_TIMING_AC_SEG1_MASK) >> ++ CAN_TIMING_AC_SEG1_BITOFF)); ++ netdev_info(ndev, " ac_seg2(22:16): 0x%02x\n", ++ (u32)((reg_val & CAN_TIMING_AC_SEG2_MASK) >> ++ CAN_TIMING_AC_SEG2_BITOFF)); ++ netdev_info(ndev, " ac_sjw (30:24): 0x%02x\n", ++ (u32)((reg_val & CAN_TIMING_AC_SJW_MASK) >> ++ CAN_TIMING_AC_SJW_BITOFF)); + -+ aspeed_intc0_disable_swint(intc_ic); -+ aspeed_intc0_disable_intbank(intc_ic); -+ aspeed_intc0_disable_intm(intc_ic); ++ reg_val = readl(priv->reg_base + CAN_FD_SEG); ++ netdev_info(ndev, "(REG008) CAN_FD_SEG = 0x%08x\n", reg_val); ++ netdev_info(ndev, " fd_seg1 (7:0): 0x%02x\n", ++ (u32)((reg_val & CAN_TIMING_FD_SEG1_MASK) >> ++ CAN_TIMING_FD_SEG1_BITOFF)); ++ netdev_info(ndev, " fd_seg2(22:16): 0x%02x\n", ++ (u32)((reg_val & CAN_TIMING_FD_SEG2_MASK) >> ++ CAN_TIMING_FD_SEG2_BITOFF)); ++ netdev_info(ndev, " fd_sjw (30:24): 0x%02x\n", ++ (u32)((reg_val & CAN_TIMING_FD_SJW_MASK) >> ++ CAN_TIMING_FD_SJW_BITOFF)); + -+ raw_spin_lock_init(&intc_ic->intc_lock); ++ reg_val = readl(priv->reg_base + CAN_BITITME); ++ netdev_info(ndev, "(REG010) CAN_BITITME = 0x%08x\n", reg_val); ++ netdev_info(ndev, " prescaler (4:0): 0x%02x\n", ++ (u32)((reg_val & CAN_TIMING_PRESC_MASK) >> ++ CAN_TIMING_PRESC_BITOFF)); ++ netdev_info(ndev, " fd_sspoff(15:8): 0x%02x\n", ++ (u32)((reg_val & CAN_TIMING_FD_SSPOFF_MASK) >> ++ CAN_TIMING_FD_SSPOFF_BITOFF)); + -+ parent_domain = irq_find_host(parent); -+ if (!parent_domain) { -+ pr_err("unable to obtain parent domain\n"); -+ return -ENODEV; -+ } ++ reg_val = readl(priv->reg_base + CAN_INTF); ++ netdev_info(ndev, "(REG014) CAN_INTF = 0x%08x\n", reg_val); ++ netdev_info(ndev, " EIF (1): %d\n", (reg_val & CAN_INT_EIF_BIT) ? 1 : 0); ++ netdev_info(ndev, " TSIF (2): %d\n", (reg_val & CAN_INT_TSIF_BIT) ? 1 : 0); ++ netdev_info(ndev, " TPIF (3): %d\n", (reg_val & CAN_INT_TPIF_BIT) ? 1 : 0); ++ netdev_info(ndev, " RAFIF (4): %d\n", (reg_val & CAN_INT_RAFIF_BIT) ? 1 : 0); ++ netdev_info(ndev, " RFIF (5): %d\n", (reg_val & CAN_INT_RFIF_BIT) ? 1 : 0); ++ netdev_info(ndev, " ROIF (6): %d\n", (reg_val & CAN_INT_ROIF_BIT) ? 1 : 0); ++ netdev_info(ndev, " RIF (7): %d\n", (reg_val & CAN_INT_RIF_BIT) ? 1 : 0); ++ netdev_info(ndev, " BEIF (8): %d\n", (reg_val & CAN_INT_BEIF_BIT) ? 1 : 0); ++ netdev_info(ndev, " EPIF (10): %d\n", (reg_val & CAN_INT_EPIF_BIT) ? 1 : 0); ++ netdev_info(ndev, " EPASS(30): %d\n", (reg_val & CAN_EPASS_BIT) ? 1 : 0); ++ netdev_info(ndev, " EWARN(31): %d\n", (reg_val & CAN_INT_EWARN_BIT) ? 1 : 0); + -+ 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; -+ } ++ reg_val = readl(priv->reg_base + CAN_INTE); ++ netdev_info(ndev, "(REG018) CAN_INTE = 0x%08x\n", reg_val); ++ netdev_info(ndev, " EIE (1): %d\n", (reg_val & CAN_INT_EIE_BIT) ? 1 : 0); ++ netdev_info(ndev, " TSIE (2): %d\n", (reg_val & CAN_INT_TSIE_BIT) ? 1 : 0); ++ netdev_info(ndev, " TPIE (3): %d\n", (reg_val & CAN_INT_TPIE_BIT) ? 1 : 0); ++ netdev_info(ndev, " RAFIE (4): %d\n", (reg_val & CAN_INT_RAFIE_BIT) ? 1 : 0); ++ netdev_info(ndev, " RFIE (5): %d\n", (reg_val & CAN_INT_RFIE_BIT) ? 1 : 0); ++ netdev_info(ndev, " ROIE (6): %d\n", (reg_val & CAN_INT_ROIE_BIT) ? 1 : 0); ++ netdev_info(ndev, " RIE (7): %d\n", (reg_val & CAN_INT_RIE_BIT) ? 1 : 0); ++ netdev_info(ndev, " BEIE (8): %d\n", (reg_val & CAN_INT_BEIE_BIT) ? 1 : 0); ++ netdev_info(ndev, " EPIE (10): %d\n", (reg_val & CAN_INT_EPIE_BIT) ? 1 : 0); + -+ ret = aspeed_intc0_init_gic_ranges(intc_ic, node, parent); -+ if (ret < 0) -+ goto err_ioumap; ++ reg_val = readl(priv->reg_base + CAN_TSTAT); ++ netdev_info(ndev, "(REG01C) CAN_TSTAT = 0x%08x\n", reg_val); ++ netdev_info(ndev, " TSTAT1 (10:8): 0x%02x\n", ++ (u32)((reg_val & CAN_TSTAT1_MASK) >> CAN_TSTAT1_BITOFF)); ++ netdev_info(ndev, " TSTAT2(26:24): 0x%02x\n", ++ (u32)((reg_val & CAN_TSTAT2_MASK) >> CAN_TSTAT2_BITOFF)); ++ netdev_info(ndev, " 000 : no tx\n"); ++ netdev_info(ndev, " 001 : on-going\n"); ++ netdev_info(ndev, " 010 : lost arbitration\n"); ++ netdev_info(ndev, " 011 : transmitted\n"); ++ netdev_info(ndev, " 100 : aborted\n"); ++ netdev_info(ndev, " 101 : disturbed\n"); ++ netdev_info(ndev, " 110 : reject\n"); + -+ return 0; ++ reg_val = readl(priv->reg_base + CAN_CTRL); ++ netdev_info(ndev, "(REG028) CAN_CTRL = 0x%08x\n", reg_val); ++ netdev_info(ndev, " BUSOFF (0): %d\n", (reg_val & CAN_CTRL_BUSOFF_BIT) ? 1 : 0); ++ netdev_info(ndev, " LBMIMOD (5): %d\n", (reg_val & CAN_CTRL_LBMIMOD_BIT) ? 1 : 0); ++ netdev_info(ndev, " LBMEMOD (6): %d\n", (reg_val & CAN_CTRL_LBMEMOD_BIT) ? 1 : 0); ++ netdev_info(ndev, " RST (7): %d\n", (reg_val & CAN_CTRL_RST_BIT) ? 1 : 0); ++ netdev_info(ndev, " TPE (12): %d\n", (reg_val & CAN_CTRL_TPE_BIT) ? 1 : 0); ++ netdev_info(ndev, " STBY (13): %d\n", (reg_val & CAN_CTRL_STBY_BIT) ? 1 : 0); ++ netdev_info(ndev, " TBSEL (15): %d\n", (reg_val & CAN_CTRL_TBSEL_BIT) ? 1 : 0); ++ netdev_info(ndev, " TTBM (20): %d\n", (reg_val & CAN_CTRL_TTBM_BIT) ? 1 : 0); ++ netdev_info(ndev, " TSMODE (21): %d\n", (reg_val & CAN_CTRL_TSMODE_BIT) ? 1 : 0); ++ netdev_info(ndev, " TSNEXT (22): %d\n", (reg_val & CAN_CTRL_TSNEXT_BIT) ? 1 : 0); ++ netdev_info(ndev, " RSTAT (25:24): 0x%02x\n", ++ (u32)((reg_val & CAN_CTRL_RSTAT_NOT_EMPTY_MASKT) >> 24)); ++ netdev_info(ndev, " RREL (28): %d\n", (reg_val & CAN_CTRL_RREL_BIT) ? 1 : 0); + -+err_ioumap: -+ iounmap(intc_ic->base); -+err_free_ic: -+ kfree(intc_ic); -+ return ret; ++ reg_val = readl(priv->reg_base + CAN_ERR_STAT); ++ netdev_info(ndev, "(REG02C) ERR_STAT = 0x%08x\n", reg_val); ++ netdev_info(ndev, " EWL (3:0): 0x%02x\n", ++ (u32)((reg_val & CAN_ERR_EWL_MASK) >> CAN_ERR_EWL_BITOFF)); ++ netdev_info(ndev, " AFWL (7:4): 0x%02x\n", ++ (u32)((reg_val & CAN_ERR_AFWL_MASK) >> CAN_ERR_AFWL_BITOFF)); ++ netdev_info(ndev, " ALC (12:8): 0x%02x\n", ++ (u32)((reg_val & CAN_ERR_ALC_MASK) >> CAN_ERR_ALC_BITOFF)); ++ netdev_info(ndev, " KOER (15:13): 0x%02x\n", ++ (u32)((reg_val & CAN_ERR_KOER_MASK) >> CAN_ERR_KOER_BITOFF)); ++ netdev_info(ndev, " 000 : no error\n"); ++ netdev_info(ndev, " 001 : bit error\n"); ++ netdev_info(ndev, " 010 : form error\n"); ++ netdev_info(ndev, " 011 : stuff error\n"); ++ netdev_info(ndev, " 100 : ack error\n"); ++ netdev_info(ndev, " 101 : crc error\n"); ++ netdev_info(ndev, " 110 : other error\n"); ++ netdev_info(ndev, " RECNT (23:16): 0x%02x\n", ++ (u32)((reg_val & CAN_ERR_RECNT_MASK) >> CAN_ERR_RECNT_BITOFF)); ++ netdev_info(ndev, " TECNT (31:24): 0x%02x\n", ++ (u32)((reg_val & CAN_ERR_TECNT_MASK) >> CAN_ERR_TECNT_BITOFF)); ++ ++ for (i = 0; i < 0x50; i += 4) ++ netdev_info(ndev, "REG(%03x): 0x%08x\n", i, readl(priv->reg_base + i)); +} + -+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-04-08 18:03:48.193707458 +0000 -@@ -0,0 +1,254 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Aspeed Interrupt Controller. -+ * -+ * Copyright (C) 2023 ASPEED Technology Inc. -+ */ ++static int aspeed_can_set_bittiming(struct net_device *ndev) ++{ ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ struct can_bittiming *bt = &priv->can.bittiming; ++ struct can_bittiming *dbt = &priv->can.data_bittiming; ++ u32 btr0, btr1; ++ u32 can_fd_ssp; + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++ /* check whether the CAN controller is in reset mode */ ++ if (!aspeed_can_check_reset_mode(ndev)) { ++ netdev_alert(ndev, ++ "BUG! Cannot set bittiming - not in reset mode\n"); ++ return -EPERM; ++ } ++ ++ /* parameter sanity */ ++ if (bt->brp < 1 || bt->prop_seg + bt->phase_seg1 < 1 || ++ bt->phase_seg2 < 1 || bt->sjw < 1) { ++ netdev_alert(ndev, ++ "invalid bittiming parameters\n"); ++ netdev_alert(ndev, ++ "brp: %x, prop: %x, seg1: %x, seg2: %x, sjw: %x\n", ++ bt->brp, bt->prop_seg, bt->phase_seg1, ++ bt->phase_seg2, bt->sjw); ++ return -EPERM; ++ } + -+#define INTC1_IER 0x100 -+#define INTC1_ISR 0x104 -+#define INTC1_IRQS_PER_BANK 32 -+#define INTC1_BANK_NUM 6 ++ /* setting prescaler value in PRESC Register */ ++ btr0 = (bt->brp - 1); + -+struct aspeed_intc_ic { -+ void __iomem *base; -+ raw_spinlock_t intc_lock; -+ struct irq_domain *irq_domain; -+}; ++ /* setting time segment 1 in SEG_1 Register */ ++ btr1 = (1 + bt->prop_seg + bt->phase_seg1 - 2); + -+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; ++ /* Setting Time Segment 2 in SEG_2 Register */ ++ btr1 |= (bt->phase_seg2 - 1) << 16; + -+ chained_irq_enter(chip, desc); ++ /* Setting Synchronous jump width in BTR Register */ ++ btr1 |= (bt->sjw - 1) << 24; + -+ for (int bank = 0; bank < INTC1_BANK_NUM; bank++) { -+ status = readl(intc_ic->base + INTC1_ISR + (0x10 * bank)); -+ if (!status) -+ continue; ++ writel(btr1, priv->reg_base + CAN_AC_SEG); + -+ 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)); ++ if (dbt->prop_seg != 0 && dbt->phase_seg1 != 0 && ++ dbt->phase_seg2 != 0) { ++ if (bt->brp != dbt->brp) { ++ netdev_alert(ndev, ++ "nominal (%d) and data (%d) prescaler isn't the same\n", ++ bt->brp, dbt->brp); ++ return -EPERM; + } -+ } + -+ chained_irq_exit(chip, desc); -+} ++ if (dbt->sjw < 1) { ++ netdev_alert(ndev, ++ "invalid data sjw %x\n", dbt->sjw); ++ return -EPERM; ++ } + -+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; ++ /* Setting Time Segment 1 in BTR Register */ ++ btr1 = 1 + dbt->prop_seg + dbt->phase_seg1 - 2; + -+ 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)); -+} ++ /* Setting Time Segment 2 in BTR Register */ ++ btr1 |= (dbt->phase_seg2 - 1) << 16; + -+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; ++ /* Setting Synchronous jump width in BTR Register */ ++ btr1 |= (dbt->sjw - 1) << 24; + -+ 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)); -+} ++ writel(btr1, priv->reg_base + CAN_FD_SEG); + -+static struct irq_chip aspeed_intc_chip = { -+ .name = "ASPEED INTC1", -+ .irq_mask = aspeed_intc1_irq_mask, -+ .irq_unmask = aspeed_intc1_irq_unmask, -+}; ++ /* seg_1 + 1 */ ++ can_fd_ssp = 1 + dbt->prop_seg + dbt->phase_seg1 + 1; + -+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; ++ btr0 |= can_fd_ssp << 8; ++ } + -+ *hwirq = fwspec->param[0]; -+ *type = IRQ_TYPE_LEVEL_HIGH; -+ return 0; -+} ++ writel(btr0 | 0x10000000, priv->reg_base + CAN_BITITME); + -+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) ++static int aspeed_can_chip_start(struct net_device *ndev) +{ -+ 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); ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ int err; + -+ 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; ++ /* Check if it is in reset mode */ ++ err = aspeed_can_set_reset_mode(ndev); ++ if (err < 0) ++ return err; ++ ++ err = aspeed_can_set_bittiming(ndev); ++ if (err < 0) ++ return err; ++ ++ /* Always config to FD mode since it is ++ * backward compatibility with CAN2.0B. ++ */ ++ aspeed_can_fd_init(ndev); ++ ++ err = aspeed_can_exit_reset_mode(ndev); ++ if (err < 0) ++ return err; + -+ if (readl(sel) & mask) { -+ writel(readl(sel) & ~mask, sel); -+ if (readl(sel) & mask) -+ return -EACCES; ++ aspeed_can_err_init(ndev); ++ aspeed_can_interrupt_conf(ndev); ++ ++ aspeed_can_tb_mode_conf(ndev); ++ ++ aspeed_can_loopback_ext_conf(ndev, false); ++ if (priv->flag & ASPEED_CAN_INTERNEL_LOOPBACK) { ++ aspeed_can_loopback_int_conf(ndev, true); ++ aspeed_can_sack_conf(ndev, true); ++ } else { ++ if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) { ++ aspeed_can_loopback_ext_conf(ndev, true); ++ aspeed_can_sack_conf(ndev, true); + } ++ aspeed_can_loopback_int_conf(ndev, false); + } + ++ priv->can.state = CAN_STATE_ERROR_ACTIVE; ++ priv->frame_handle = 0; ++ + 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) ++static int aspeed_can_do_set_mode(struct net_device *ndev, enum can_mode mode) +{ -+ struct of_phandle_args parent_irq; -+ int i, j, n, ret; ++ int ret; + -+ if (!of_device_is_compatible(parent_node, "aspeed,ast2700-intc0-ic")) -+ return -ENOENT; ++ switch (mode) { ++ case CAN_MODE_START: ++ ret = aspeed_can_chip_start(ndev); ++ if (ret < 0) { ++ netdev_err(ndev, "aspeed_can_chip_start failed!\n"); ++ return ret; ++ } ++ netif_wake_queue(ndev); ++ break; ++ default: ++ netdev_err(ndev, "unexpect can mode: %d\n", (u32)mode); ++ ret = -EOPNOTSUPP; ++ break; ++ } + -+ n = of_property_count_elems_of_size(node, "aspeed,interrupt-ranges", sizeof(u32)); -+ if (n <= 0 || n % 4) -+ return -EINVAL; ++ return ret; ++} + -+ /* -+ * 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; ++static void aspeed_can_write_frame(struct net_device *ndev, ++ struct sk_buff *skb) ++{ ++ u32 id; ++ struct canfd_frame *cf = (struct canfd_frame *)skb->data; ++ u32 i; ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ u32 buf_ctrl = 0; ++ u32 can_ctrl; ++ u32 can_type; + -+ target = of_find_node_by_phandle(parent_handle); -+ if (!target) -+ continue; ++ can_ctrl = readl(priv->reg_base + CAN_CTRL); + -+ if (target != parent_node) { -+ of_node_put(target); -+ continue; -+ } ++ /* Watch carefully on the bit sequence */ ++ if (cf->can_id & CAN_EFF_FLAG) { ++ id = (cf->can_id & CAN_EFF_MASK) << CAN_BUF_ID_EFF_BITOFF; ++ buf_ctrl |= CAN_BUF_IDE_BIT; ++ } else { ++ /* Standard CAN ID format */ ++ id = (cf->can_id & CAN_SFF_MASK) << CAN_BUF_ID_BFF_BITOFF; ++ } + -+ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", -+ i * 4 + 1, &count); -+ if (ret) -+ return ret; ++ if (cf->can_id & CAN_RTR_FLAG) ++ buf_ctrl |= CAN_BUF_RMF_BIT; + -+ ret = of_property_read_u32_index(node, "aspeed,interrupt-ranges", -+ i * 4 + 3, &base_irq); -+ if (ret) -+ return ret; ++ buf_ctrl |= can_fd_len2dlc(cf->len); + -+ for (j = 0; j < count; j++) { -+ int irq; ++ if (can_is_canfd_skb(skb)) { ++ buf_ctrl |= CAN_BUF_FDF_BIT; ++ if (cf->flags & CANFD_BRS) ++ buf_ctrl |= CAN_BUF_BRS_BIT; ++ } + -+ 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; ++ can_type = priv->frame_handle << CAN_BUF_HANDLE_BITOFF; + -+ irq_set_chained_handler_and_data(irq, -+ aspeed_intc1_ic_irq_handler, -+ intc_ic); -+ } ++ writel(id, priv->reg_base + CAN_TBUF_ID); ++ writel(buf_ctrl, priv->reg_base + CAN_TBUF_CTL); ++ writel(can_type, priv->reg_base + CAN_TBUF_TYPE); + -+ of_node_put(target); -+ } ++ writel(0x0, priv->reg_base + CAN_TBUF_TYPE); ++ writel(0x0, priv->reg_base + CAN_TBUF_ACF); + -+ return 0; -+} ++ if (cf->can_id & CAN_RTR_FLAG) ++ return; + -+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)); ++ for (i = 0; i < (cf->len / 4 + 3) * 4; i += 4) { ++ writel(*(u32 *)(cf->data + i), ++ priv->reg_base + CAN_TBUF_DATA + i); ++ } +} + -+static int aspeed_intc1_ic_of_init(struct device_node *node, struct device_node *parent) ++static int aspeed_can_start_frame_xmit(struct sk_buff *skb, ++ struct net_device *ndev) +{ -+ struct aspeed_intc_ic *intc_ic; -+ int ret = 0; ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ u32 i = 0; ++ u32 can_ctrl; ++ u32 int_flag; ++ u32 skb_idx; ++ int ret; + -+ if (!parent) { -+ pr_err("missing parent interrupt node\n"); -+ return -ENODEV; ++ /* avoid transmitting data finish suddenly */ ++ while (i < 3) { ++ can_ctrl = readl(priv->reg_base + CAN_CTRL); ++ int_flag = readl(priv->reg_base + CAN_INTF); ++ i++; + } + -+ if (!irq_find_host(parent)) -+ return -ENODEV; ++ /* check whether STB or PTB is full */ ++ if ((can_ctrl & CAN_CTRL_TBSEL_BIT) && ++ (can_ctrl & CAN_CTRL_TSFF_BIT)) ++ return -ENOSPC; + -+ intc_ic = kzalloc(sizeof(*intc_ic), GFP_KERNEL); ++ if (!(can_ctrl & CAN_CTRL_TBSEL_BIT) && ++ ((can_ctrl & CAN_CTRL_TPE_BIT) || ++ (int_flag & CAN_INT_TPIF_BIT))) ++ return -ENOSPC; + -+ if (!intc_ic) -+ return -ENOMEM; ++ if (priv->frame_handle == 0x100) ++ priv->frame_handle = 0; + -+ 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; ++ /* Use skb idex to check whether ++ * the same handle already in STB. ++ */ ++ skb_idx = aspeed_can_get_skb_idx(ndev, priv->frame_handle); ++ if (skb_idx != STB_INVALID_SKB_IDX) { ++ netdev_err(ndev, "repeat handle %d\n", priv->frame_handle); ++ return -ENOSPC; + } + -+ raw_spin_lock_init(&intc_ic->intc_lock); ++ aspeed_can_write_frame(ndev, skb); + -+ 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; -+ } ++ if (can_ctrl & CAN_CTRL_TBSEL_BIT) { ++ /* STB */ ++ ret = can_put_echo_skb(skb, ndev, priv->head_ptr->skb_idx, 0); ++ if (ret) { ++ netdev_err(ndev, "fail to put skb for stb %d\n", ret); ++ return ret; ++ } + -+ ret = aspeed_intc1_interrupt_ranges(intc_ic, node, parent); -+ if (ret < 0) -+ goto err_iounmap; ++ priv->head_ptr->handle = priv->frame_handle; ++ priv->head_ptr = priv->head_ptr->next; + -+ return 0; ++ /* STB is full */ ++ if (priv->head_ptr == priv->tail_ptr) ++ netif_stop_queue(ndev); + -+err_iounmap: -+ iounmap(intc_ic->base); -+err_free_ic: -+ kfree(intc_ic); -+ return ret; -+} ++ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_TSNEXT_BIT); + -+IRQCHIP_DECLARE(ast2700_intc1_ic, "aspeed,ast2700-intc1-ic", aspeed_intc1_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 2026-04-08 18:03:44.029783536 +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. ++ /* no frame is transmitting or there is no unhandled finish flag */ ++ if ((priv->stb_mode_policy & STB_TX_MODE_ONE) && ++ !(can_ctrl & CAN_CTRL_TSONE_BIT) && ++ !(int_flag & CAN_INT_TSIF_BIT)) ++ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_TSONE_BIT); ++ else if ((priv->stb_mode_policy & STB_TX_MODE_ALL) && ++ !(can_ctrl & CAN_CTRL_TSALL_BIT) && ++ !(int_flag & CAN_INT_TSIF_BIT)) ++ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_TSALL_BIT); ++ } else { ++ /* PTB */ ++ ret = can_put_echo_skb(skb, ndev, 0, 0); ++ if (ret) { ++ netdev_err(ndev, "fail to put skb for ptb %d\n", ret); ++ return ret; ++ } + -+ 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-04-08 18:03:44.029783536 +0000 -@@ -0,0 +1,2 @@ -+obj-$(CONFIG_JTAG) += jtag.o -+obj-$(CONFIG_JTAG_ASPEED) += jtag-aspeed.o -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 2026-04-08 18:03:48.170707878 +0000 -@@ -0,0 +1,1657 @@ -+// SPDX-License-Identifier: GPL-2.0 -+// Copyright (c) 2018 Mellanox Technologies. All rights reserved. -+// Copyright (c) 2018 Oleksandr Shamray -+// Copyright (c) 2019 Intel Corporation ++ netif_stop_queue(ndev); ++ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_TPE_BIT); ++ } + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++ priv->frame_handle++; + -+#define ASPEED_JTAG_DATA 0x00 -+#define ASPEED_JTAG_INST 0x04 -+#define ASPEED_JTAG_CTRL 0x08 -+#define ASPEED_JTAG_ISR 0x0C -+#define ASPEED_JTAG_SW 0x10 -+#define ASPEED_JTAG_TCK 0x14 -+#define ASPEED_JTAG_EC 0x18 ++ return 0; ++} + -+#define ASPEED_JTAG_DATA_MSB 0x01 -+#define ASPEED_JTAG_DATA_CHUNK_SIZE 0x20 -+#define ASPEED_JTAG_HW2_DATA_CHUNK_SIZE 512 ++static netdev_tx_t aspeed_can_start_xmit(struct sk_buff *skb, ++ struct net_device *ndev) ++{ ++ int ret; ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ unsigned long flags; + -+/* ASPEED_JTAG_CTRL: Engine Control 24xx and 25xx series*/ -+#define ASPEED_JTAG_CTL_ENG_EN BIT(31) -+#define ASPEED_JTAG_CTL_ENG_OUT_EN BIT(30) -+#define ASPEED_JTAG_CTL_FORCE_TMS BIT(29) -+#define ASPEED_JTAG_CTL_IR_UPDATE BIT(26) -+#define ASPEED_JTAG_CTL_INST_LEN(x) ((x) << 20) -+#define ASPEED_JTAG_CTL_LASPEED_INST BIT(17) -+#define ASPEED_JTAG_CTL_INST_EN BIT(16) -+#define ASPEED_JTAG_CTL_DR_UPDATE BIT(10) -+#define ASPEED_JTAG_CTL_DATA_LEN(x) ((x) << 4) -+#define ASPEED_JTAG_CTL_LASPEED_DATA BIT(1) -+#define ASPEED_JTAG_CTL_DATA_EN BIT(0) ++ if (can_dev_dropped_skb(ndev, skb)) ++ return NET_XMIT_DROP; + -+/* ASPEED_JTAG_CTRL: Engine Control 26xx series*/ -+#define ASPEED_JTAG_CTL_26XX_RESET_FIFO BIT(21) -+#define ASPEED_JTAG_CTL_26XX_FIFO_MODE_CTRL BIT(20) -+#define ASPEED_JTAG_CTL_26XX_TRANS_LEN(x) ((x) << 8) -+#define ASPEED_JTAG_CTL_26XX_TRANS_MASK GENMASK(17, 8) -+#define ASPEED_JTAG_CTL_26XX_MSB_FIRST BIT(6) -+#define ASPEED_JTAG_CTL_26XX_TERM_TRANS BIT(5) -+#define ASPEED_JTAG_CTL_26XX_LASPEED_TRANS BIT(4) -+#define ASPEED_JTAG_CTL_26XX_INST_EN BIT(1) ++ spin_lock_irqsave(&priv->tx_lock, flags); + -+/* ASPEED_JTAG_ISR : Interrupt status and enable */ -+#define ASPEED_JTAG_ISR_INST_PAUSE BIT(19) -+#define ASPEED_JTAG_ISR_INST_COMPLETE BIT(18) -+#define ASPEED_JTAG_ISR_DATA_PAUSE BIT(17) -+#define ASPEED_JTAG_ISR_DATA_COMPLETE BIT(16) -+#define ASPEED_JTAG_ISR_INST_PAUSE_EN BIT(3) -+#define ASPEED_JTAG_ISR_INST_COMPLETE_EN BIT(2) -+#define ASPEED_JTAG_ISR_DATA_PAUSE_EN BIT(1) -+#define ASPEED_JTAG_ISR_DATA_COMPLETE_EN BIT(0) -+#define ASPEED_JTAG_ISR_INT_EN_MASK GENMASK(3, 0) -+#define ASPEED_JTAG_ISR_INT_MASK GENMASK(19, 16) ++ ret = aspeed_can_start_frame_xmit(skb, ndev); + -+/* ASPEED_JTAG_SW : Software Mode and Status */ -+#define ASPEED_JTAG_SW_MODE_EN BIT(19) -+#define ASPEED_JTAG_SW_MODE_TCK BIT(18) -+#define ASPEED_JTAG_SW_MODE_TMS BIT(17) -+#define ASPEED_JTAG_SW_MODE_TDIO BIT(16) ++ spin_unlock_irqrestore(&priv->tx_lock, flags); + -+/* ASPEED_JTAG_TCK : TCK Control */ -+#define ASPEED_JTAG_TCK_DIVISOR_MASK GENMASK(11, 0) -+#define ASPEED_JTAG_TCK_GET_DIV(x) ((x) & ASPEED_JTAG_TCK_DIVISOR_MASK) ++ if (ret) { ++ netdev_err(ndev, "Fail to transmit data!\n"); ++ netif_stop_queue(ndev); ++ return NET_XMIT_DROP; ++ } + -+/* ASPEED_JTAG_EC : Controller set for go to IDLE */ -+#define ASPEED_JTAG_EC_TRSTn_HIGH BIT(31) -+#define ASPEED_JTAG_EC_GO_IDLE BIT(0) ++ return NETDEV_TX_OK; ++} + -+#define ASPEED_JTAG_IOUT_LEN(len) \ -+ (ASPEED_JTAG_CTL_ENG_EN | \ -+ ASPEED_JTAG_CTL_ENG_OUT_EN | \ -+ ASPEED_JTAG_CTL_INST_LEN(len)) ++static int aspeed_can_rx(struct net_device *ndev) ++{ ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ struct net_device_stats *stats = &ndev->stats; ++ struct canfd_frame *cf; ++ struct sk_buff *skb; ++ u32 data; ++ u32 rx_stat; ++ u32 buf_ctrl_reg; ++ u32 reg_val; ++ u32 i; + -+#define ASPEED_JTAG_DOUT_LEN(len) \ -+ (ASPEED_JTAG_CTL_ENG_EN | \ -+ ASPEED_JTAG_CTL_ENG_OUT_EN | \ -+ ASPEED_JTAG_CTL_DATA_LEN(len)) ++ rx_stat = readl(priv->reg_base + CAN_CTRL); ++ if (!(rx_stat & CAN_CTRL_RSTAT_NOT_EMPTY_MASKT)) ++ return 0; + -+#define ASPEED_JTAG_TRANS_LEN(len) \ -+ (ASPEED_JTAG_CTL_ENG_EN | \ -+ ASPEED_JTAG_CTL_ENG_OUT_EN | \ -+ ASPEED_JTAG_CTL_26XX_TRANS_LEN(len)) ++ buf_ctrl_reg = readl(priv->reg_base + CAN_RBUF_CTL); ++ if (buf_ctrl_reg & CAN_BUF_FDF_BIT) ++ skb = alloc_canfd_skb(ndev, &cf); ++ else ++ skb = alloc_can_skb(ndev, (struct can_frame **)&cf); + -+#define ASPEED_JTAG_SW_TDIO (ASPEED_JTAG_SW_MODE_EN | ASPEED_JTAG_SW_MODE_TDIO) ++ if (!skb) { ++ stats->rx_dropped++; ++ return 0; ++ } + -+#define ASPEED_JTAG_GET_TDI(direction, byte) \ -+ (((direction) & JTAG_WRITE_XFER) ? byte : UINT_MAX) ++ reg_val = readl(priv->reg_base + CAN_RBUF_ID); ++ if (buf_ctrl_reg & CAN_BUF_IDE_BIT) { ++ cf->can_id = reg_val & CAN_BUF_ID_EFF_MASK; ++ cf->can_id |= CAN_EFF_FLAG; ++ } else { ++ cf->can_id = (reg_val & CAN_BUF_ID_BFF_MASK) >> ++ CAN_BUF_ID_BFF_BITOFF; ++ } + -+#define ASPEED_JTAG_TCK_WAIT 10 -+#define ASPEED_JTAG_RESET_CNTR 10 -+#define WAIT_ITERATIONS 300 ++ if (buf_ctrl_reg & CAN_BUF_RMF_BIT) ++ cf->can_id |= CAN_RTR_FLAG; + -+/* Use this macro to switch between HW mode 1(comment out) and 2(defined) */ -+#define ASPEED_JTAG_HW_MODE_2_ENABLE 1 ++ if (buf_ctrl_reg & CAN_BUF_FDF_BIT) ++ cf->len = can_fd_dlc2len(buf_ctrl_reg & CAN_BUF_DLC_MASK); ++ else ++ cf->len = can_cc_dlc2len(buf_ctrl_reg & CAN_BUF_DLC_MASK); + -+/* ASPEED JTAG HW MODE 2 (Only supported in AST26xx series) */ -+#define ASPEED_JTAG_SHDATA 0x20 -+#define ASPEED_JTAG_SHINST 0x24 -+#define ASPEED_JTAG_PADCTRL0 0x28 -+#define ASPEED_JTAG_PADCTRL1 0x2C -+#define ASPEED_JTAG_SHCTRL 0x30 -+#define ASPEED_JTAG_GBLCTRL 0x34 -+#define ASPEED_JTAG_INTCTRL 0x38 -+#define ASPEED_JTAG_STAT 0x3C ++ /* Check the frame received is FD or not*/ ++ for (i = 0; i < cf->len; i += 4) { ++ data = readl(priv->reg_base + CAN_RBUF_DATA + i); ++ *(u32 *)(cf->data + i) = data; ++ } + -+/* ASPEED_JTAG_PADCTRLx : Padding control 0 and 1 */ -+#define ASPEED_JTAG_PADCTRL_PAD_DATA BIT(24) -+#define ASPEED_JTAG_PADCTRL_POSTPAD(x) (((x) & GENMASK(8, 0)) << 12) -+#define ASPEED_JTAG_PADCTRL_PREPAD(x) (((x) & GENMASK(8, 0)) << 0) ++ if (!(cf->can_id & CAN_RTR_FLAG)) ++ stats->rx_bytes += cf->len; + -+/* ASPEED_JTAG_SHCTRL: Shift Control */ -+#define ASPEED_JTAG_SHCTRL_FRUN_TCK_EN BIT(31) -+#define ASPEED_JTAG_SHCTRL_STSHIFT_EN BIT(30) -+#define ASPEED_JTAG_SHCTRL_TMS(x) (((x) & GENMASK(13, 0)) << 16) -+#define ASPEED_JTAG_SHCTRL_POST_TMS(x) (((x) & GENMASK(2, 0)) << 13) -+#define ASPEED_JTAG_SHCTRL_PRE_TMS(x) (((x) & GENMASK(2, 0)) << 10) -+#define ASPEED_JTAG_SHCTRL_PAD_SEL0 (0) -+#define ASPEED_JTAG_SHCTRL_PAD_SEL1 BIT(9) -+#define ASPEED_JTAG_SHCTRL_END_SHIFT BIT(8) -+#define ASPEED_JTAG_SHCTRL_START_SHIFT BIT(7) -+#define ASPEED_JTAG_SHCTRL_LWRDT_SHIFT(x) ((x) & GENMASK(6, 0)) ++ stats->rx_packets++; + -+#define ASPEED_JTAG_END_SHIFT_DISABLED 0 ++ /* release frame */ ++ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_RREL_BIT); + -+/* ASPEED_JTAG_GBLCTRL : Global Control */ -+#define ASPEED_JTAG_GBLCTRL_ENG_MODE_EN BIT(31) -+#define ASPEED_JTAG_GBLCTRL_ENG_OUT_EN BIT(30) -+#define ASPEED_JTAG_GBLCTRL_FORCE_TMS BIT(29) -+#define ASPEED_JTAG_GBLCTRL_SHIFT_COMPLETE BIT(28) -+#define ASPEED_JTAG_GBLCTRL_RESET_FIFO BIT(25) -+#define ASPEED_JTAG_GBLCTRL_FIFO_CTRL_MODE BIT(24) -+#define ASPEED_JTAG_GBLCTRL_UPDT_SHIFT(x) (((x) & GENMASK(9, 7)) << 13) -+#define ASPEED_JTAG_GBLCTRL_STSHIFT(x) (((x) & GENMASK(0, 0)) << 16) -+#define ASPEED_JTAG_GBLCTRL_TRST BIT(15) -+#define ASPEED_JTAG_CLK_DIVISOR_MASK GENMASK(11, 0) -+#define ASPEED_JTAG_CLK_GET_DIV(x) ((x) & ASPEED_JTAG_CLK_DIVISOR_MASK) ++ netif_receive_skb(skb); + -+/* ASPEED_JTAG_INTCTRL: Interrupt Control */ -+#define ASPEED_JTAG_INTCTRL_SHCPL_IRQ_EN BIT(16) -+#define ASPEED_JTAG_INTCTRL_SHCPL_IRQ_STAT BIT(0) ++ return 1; ++} + -+/* ASPEED_JTAG_STAT: JTAG HW mode 2 status */ -+#define ASPEED_JTAG_STAT_ENG_IDLE BIT(0) ++static enum can_state aspeed_can_current_error_state(struct net_device *ndev) ++{ ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ u32 status; ++ u32 rx_cnt; ++ u32 tx_cnt; ++ u32 ctrl; + -+#define ASPEED_JTAG_MAX_PAD_SIZE 512 ++ ctrl = readl(priv->reg_base + CAN_CTRL); ++ status = readl(priv->reg_base + CAN_INTF); ++ rx_cnt = (readl(priv->reg_base + CAN_ERR_STAT) & CAN_ERR_RECNT_MASK) >> ++ CAN_ERR_RECNT_BITOFF; ++ tx_cnt = (readl(priv->reg_base + CAN_ERR_STAT) & CAN_ERR_TECNT_MASK) >> ++ CAN_ERR_TECNT_BITOFF; + -+/* Use this macro to set us delay to WA the intensive R/W FIFO usage issue */ -+#define AST26XX_FIFO_UDELAY 2 ++ if (ctrl & CAN_CTRL_BUSOFF_BIT) ++ return CAN_STATE_BUS_OFF; ++ else if ((status & CAN_EPASS_BIT) == CAN_EPASS_BIT) ++ return CAN_STATE_ERROR_PASSIVE; ++ else if (rx_cnt > 96 || tx_cnt > 96) ++ return CAN_STATE_ERROR_WARNING; ++ else ++ return CAN_STATE_ERROR_ACTIVE; ++} + -+/* Use this macro to set us delay for JTAG Master Controller to be programmed */ -+#define AST26XX_JTAG_CTRL_UDELAY 2 ++static void aspeed_can_set_error_state(struct net_device *ndev, ++ enum can_state new_state, ++ struct can_frame *cf) ++{ ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ u32 ecr = readl(priv->reg_base + CAN_ERR_STAT); ++ u32 txerr = (ecr & CAN_ERR_RECNT_MASK) >> CAN_ERR_RECNT_BITOFF; ++ u32 rxerr = (ecr & CAN_ERR_TECNT_MASK) >> CAN_ERR_TECNT_BITOFF; ++ enum can_state tx_state = txerr >= rxerr ? new_state : 0; ++ enum can_state rx_state = txerr <= rxerr ? new_state : 0; + -+#define DEBUG_JTAG ++ /* non-ERROR states are handled elsewhere */ ++ if (WARN_ON(new_state > CAN_STATE_ERROR_PASSIVE)) ++ return; + -+static const char * const regnames[] = { -+ [ASPEED_JTAG_DATA] = "ASPEED_JTAG_DATA", -+ [ASPEED_JTAG_INST] = "ASPEED_JTAG_INST", -+ [ASPEED_JTAG_CTRL] = "ASPEED_JTAG_CTRL", -+ [ASPEED_JTAG_ISR] = "ASPEED_JTAG_ISR", -+ [ASPEED_JTAG_SW] = "ASPEED_JTAG_SW", -+ [ASPEED_JTAG_TCK] = "ASPEED_JTAG_TCK", -+ [ASPEED_JTAG_EC] = "ASPEED_JTAG_EC", -+ [ASPEED_JTAG_SHDATA] = "ASPEED_JTAG_SHDATA", -+ [ASPEED_JTAG_SHINST] = "ASPEED_JTAG_SHINST", -+ [ASPEED_JTAG_PADCTRL0] = "ASPEED_JTAG_PADCTRL0", -+ [ASPEED_JTAG_PADCTRL1] = "ASPEED_JTAG_PADCTRL1", -+ [ASPEED_JTAG_SHCTRL] = "ASPEED_JTAG_SHCTRL", -+ [ASPEED_JTAG_GBLCTRL] = "ASPEED_JTAG_GBLCTRL", -+ [ASPEED_JTAG_INTCTRL] = "ASPEED_JTAG_INTCTRL", -+ [ASPEED_JTAG_STAT] = "ASPEED_JTAG_STAT", -+}; ++ can_change_state(ndev, cf, tx_state, rx_state); + -+#define ASPEED_JTAG_NAME "jtag-aspeed" ++ if (cf) { ++ cf->can_id |= CAN_ERR_CNT; ++ cf->data[6] = txerr; ++ cf->data[7] = rxerr; ++ } ++} + -+struct aspeed_jtag { -+ void __iomem *reg_base; -+ struct device *dev; -+ struct clk *pclk; -+ enum jtag_tapstate status; -+ int irq; -+ struct reset_control *rst; -+ u32 flag; -+ wait_queue_head_t jtag_wq; -+ u32 mode; -+ enum jtag_tapstate current_state; -+ u32 tck_period; -+ const struct jtag_low_level_functions *llops; -+ u32 pad_data_one[ASPEED_JTAG_MAX_PAD_SIZE / 32]; -+ u32 pad_data_zero[ASPEED_JTAG_MAX_PAD_SIZE / 32]; -+}; ++static void aspeed_can_update_error_state_after_rxtx(struct net_device *ndev) ++{ ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ enum can_state old_state = priv->can.state; ++ enum can_state new_state; + -+/* -+ * Multi generation support is enabled by fops and low level assped function -+ * mapping using asped_jtag_functions struct as config mechanism. -+ */ ++ /* changing error state due to successful frame RX/TX can only ++ * occur from these states ++ */ ++ if (old_state != CAN_STATE_ERROR_WARNING && ++ old_state != CAN_STATE_ERROR_PASSIVE) ++ return; + -+struct jtag_low_level_functions { -+ void (*output_disable)(struct aspeed_jtag *aspeed_jtag); -+ void (*master_enable)(struct aspeed_jtag *aspeed_jtag); -+ int (*xfer_push_data)(struct aspeed_jtag *aspeed_jtag, -+ enum jtag_xfer_type type, u32 bits_len); -+ int (*xfer_push_data_last)(struct aspeed_jtag *aspeed_jtag, -+ enum jtag_xfer_type type, u32 bits_len); -+ void (*xfer_sw)(struct aspeed_jtag *aspeed_jtag, struct jtag_xfer *xfer, -+ u32 *data); -+ int (*xfer_hw)(struct aspeed_jtag *aspeed_jtag, struct jtag_xfer *xfer, -+ u32 *data); -+ int (*trst_set)(struct aspeed_jtag *aspeed_jtag, u32 active); -+ void (*xfer_hw_fifo_delay)(void); -+ void (*xfer_sw_delay)(struct aspeed_jtag *aspeed_jtag); -+ irqreturn_t (*jtag_interrupt)(s32 this_irq, void *dev_id); -+}; ++ new_state = aspeed_can_current_error_state(ndev); + -+struct aspeed_jtag_functions { -+ const struct jtag_ops *aspeed_jtag_ops; -+ const struct jtag_low_level_functions *aspeed_jtag_llops; -+}; ++ if (new_state != old_state) { ++ struct sk_buff *skb; ++ struct can_frame *cf; + -+#ifdef DEBUG_JTAG -+static char *end_status_str[] = { "tlr", "idle", "selDR", "capDR", "sDR", -+ "ex1DR", "pDR", "ex2DR", "updDR", "selIR", -+ "capIR", "sIR", "ex1IR", "pIR", "ex2IR", -+ "updIR", "current" }; -+#endif ++ skb = alloc_can_err_skb(ndev, &cf); + -+static u32 aspeed_jtag_read(struct aspeed_jtag *aspeed_jtag, u32 reg) -+{ -+ u32 val = readl(aspeed_jtag->reg_base + reg); ++ aspeed_can_set_error_state(ndev, new_state, skb ? cf : NULL); + -+#ifdef DEBUG_JTAG -+ dev_dbg(aspeed_jtag->dev, "read:%s val = 0x%08x\n", regnames[reg], val); -+#endif -+ return val; ++ if (skb) ++ netif_rx(skb); ++ } +} + -+static void aspeed_jtag_write(struct aspeed_jtag *aspeed_jtag, u32 val, u32 reg) ++static void aspeed_can_err_interrupt(struct net_device *ndev, u32 isr) +{ -+#ifdef DEBUG_JTAG -+ dev_dbg(aspeed_jtag->dev, "write:%s val = 0x%08x\n", regnames[reg], -+ val); -+#endif -+ writel(val, aspeed_jtag->reg_base + reg); -+} ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ struct net_device_stats *stats = &ndev->stats; ++ struct can_frame cf = { }; ++ u32 err; ++ u32 ctrl; ++ u32 koer; ++ u32 recnt; ++ u32 tecnt; + -+static int aspeed_jtag_freq_set(struct jtag *jtag, u32 freq) -+{ -+ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); -+ unsigned long apb_frq; -+ u32 tck_val; -+ u16 div; ++ netdev_err(ndev, "in error interrupt.\n"); + -+ if (!freq) -+ return -EINVAL; ++ aspeed_can_reg_dump(ndev); + -+ apb_frq = clk_get_rate(aspeed_jtag->pclk); -+ if (!apb_frq) -+ return -EOPNOTSUPP; ++ err = readl(priv->reg_base + CAN_ERR_STAT); ++ ctrl = readl(priv->reg_base + CAN_CTRL); + -+ div = (apb_frq - 1) / freq; -+ if (div > ASPEED_JTAG_TCK_DIVISOR_MASK) -+ div = ASPEED_JTAG_TCK_DIVISOR_MASK; -+ tck_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_TCK); -+ aspeed_jtag_write(aspeed_jtag, -+ (tck_val & ~ASPEED_JTAG_TCK_DIVISOR_MASK) | div, -+ ASPEED_JTAG_TCK); -+ aspeed_jtag->tck_period = -+ DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC * (div + 1), apb_frq); -+ return 0; -+} ++ koer = (err & CAN_ERR_KOER_MASK) >> CAN_ERR_KOER_BITOFF; ++ recnt = (err & CAN_ERR_RECNT_MASK) >> CAN_ERR_RECNT_BITOFF; ++ tecnt = (err & CAN_ERR_TECNT_MASK) >> CAN_ERR_TECNT_BITOFF; + -+static int aspeed_jtag_freq_set_26xx(struct jtag *jtag, u32 freq) -+{ -+ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); -+ unsigned long apb_frq; -+ u32 tck_val; -+ u16 div; ++ if (ctrl & CAN_CTRL_BUSOFF_BIT) { ++ priv->can.state = CAN_STATE_BUS_OFF; ++ priv->can.can_stats.bus_off++; ++ /* Leave device in Config Mode in bus-off state */ ++ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_RST_BIT); ++ can_bus_off(ndev); ++ cf.can_id |= CAN_ERR_BUSOFF; ++ } else { ++ enum can_state new_state = aspeed_can_current_error_state(ndev); + -+ if (!freq) -+ return -EINVAL; ++ if (new_state != priv->can.state) ++ aspeed_can_set_error_state(ndev, new_state, &cf); ++ } + -+ apb_frq = clk_get_rate(aspeed_jtag->pclk); -+ if (!apb_frq) -+ return -EOPNOTSUPP; ++ if (isr & CAN_INT_ALIF_BIT) { ++ priv->can.can_stats.arbitration_lost++; ++ cf.can_id |= CAN_ERR_LOSTARB; ++ cf.data[0] = CAN_ERR_LOSTARB_UNSPEC; ++ } + -+ div = (apb_frq - 1) / freq; -+ tck_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_GBLCTRL); -+ aspeed_jtag_write(aspeed_jtag, -+ (tck_val & ~ASPEED_JTAG_CLK_DIVISOR_MASK) | div, -+ ASPEED_JTAG_GBLCTRL); -+ aspeed_jtag->tck_period = -+ DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC * (div + 1), apb_frq); -+ return 0; -+} ++ if (isr & CAN_INT_ROIF_BIT) { ++ stats->rx_over_errors++; ++ stats->rx_errors++; ++ cf.can_id |= CAN_ERR_CRTL; ++ cf.data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; ++ } + -+static int aspeed_jtag_freq_get(struct jtag *jtag, u32 *frq) -+{ -+ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); -+ u32 pclk; -+ u32 tck; ++ /* Check for error interrupt */ ++ if (isr & CAN_INT_BEIF_BIT) { ++ bool berr_reporting = false; + -+ pclk = clk_get_rate(aspeed_jtag->pclk); -+ tck = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_TCK); -+ *frq = pclk / (ASPEED_JTAG_TCK_GET_DIV(tck) + 1); ++ if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) { ++ berr_reporting = true; ++ cf.can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; ++ } + -+ return 0; -+} ++ if (koer == KOER_ACK_ERROR_MASK) { ++ netdev_err(ndev, "ACK error exists\n"); ++ stats->tx_errors++; ++ if (berr_reporting) { ++ cf.can_id |= CAN_ERR_ACK; ++ cf.data[3] = CAN_ERR_PROT_LOC_ACK; ++ } ++ } + -+static int aspeed_jtag_freq_get_26xx(struct jtag *jtag, u32 *frq) -+{ -+ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); -+ u32 pclk; -+ u32 tck; ++ if (koer == KOER_BIT_ERROR_MASK) { ++ netdev_err(ndev, "BIT error exists\n"); ++ stats->tx_errors++; ++ if (berr_reporting) { ++ cf.can_id |= CAN_ERR_PROT; ++ cf.data[2] = CAN_ERR_PROT_BIT; ++ } ++ } + -+ pclk = clk_get_rate(aspeed_jtag->pclk); -+ tck = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_GBLCTRL); -+ *frq = pclk / (ASPEED_JTAG_CLK_GET_DIV(tck) + 1); ++ if (koer == KOER_STUFF_ERROR_MASK) { ++ netdev_err(ndev, "STUFF error exists\n"); ++ stats->rx_errors++; ++ if (berr_reporting) { ++ cf.can_id |= CAN_ERR_PROT; ++ cf.data[2] = CAN_ERR_PROT_STUFF; ++ } ++ } + -+ return 0; -+} ++ if (koer == KOER_FORM_ERROR_MASK) { ++ netdev_err(ndev, "FORM error exists\n"); ++ stats->rx_errors++; ++ if (berr_reporting) { ++ cf.can_id |= CAN_ERR_PROT; ++ cf.data[2] = CAN_ERR_PROT_FORM; ++ } ++ } + -+static inline void aspeed_jtag_output_disable(struct aspeed_jtag *aspeed_jtag) -+{ -+ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_CTRL); -+} ++ if (koer == KOER_CRC_ERROR_MASK) { ++ netdev_err(ndev, "CRC error exists\n"); ++ stats->rx_errors++; ++ if (berr_reporting) { ++ cf.can_id |= CAN_ERR_PROT; ++ cf.data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; ++ } ++ } + -+static inline void -+aspeed_jtag_output_disable_26xx(struct aspeed_jtag *aspeed_jtag) -+{ -+ u32 reg_val; ++ priv->can.can_stats.bus_error++; ++ } + -+ reg_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_GBLCTRL) & -+ ASPEED_JTAG_CLK_DIVISOR_MASK; -+ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_CTRL); -+ aspeed_jtag_write(aspeed_jtag, reg_val, ASPEED_JTAG_GBLCTRL); ++ if (cf.can_id) { ++ struct can_frame *skb_cf; ++ struct sk_buff *skb = alloc_can_err_skb(ndev, &skb_cf); ++ ++ if (skb) { ++ skb_cf->can_id |= cf.can_id; ++ memcpy(skb_cf->data, cf.data, CAN_ERR_DLC); ++ netif_rx(skb); ++ } ++ } +} + -+static inline void aspeed_jtag_master(struct aspeed_jtag *aspeed_jtag) ++static int aspeed_can_rx_poll(struct napi_struct *napi, int quota) +{ -+ aspeed_jtag_write(aspeed_jtag, -+ (ASPEED_JTAG_CTL_ENG_EN | ASPEED_JTAG_CTL_ENG_OUT_EN), -+ ASPEED_JTAG_CTRL); ++ struct net_device *ndev = napi->dev; ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ int work_done = 0; ++ u32 rx_stat; ++ u32 ier; + -+ aspeed_jtag_write(aspeed_jtag, -+ ASPEED_JTAG_SW_MODE_EN | ASPEED_JTAG_SW_MODE_TDIO, -+ ASPEED_JTAG_SW); -+ aspeed_jtag_write(aspeed_jtag, -+ ASPEED_JTAG_ISR_INST_PAUSE | -+ ASPEED_JTAG_ISR_INST_COMPLETE | -+ ASPEED_JTAG_ISR_DATA_PAUSE | -+ ASPEED_JTAG_ISR_DATA_COMPLETE | -+ ASPEED_JTAG_ISR_INST_PAUSE_EN | -+ ASPEED_JTAG_ISR_INST_COMPLETE_EN | -+ ASPEED_JTAG_ISR_DATA_PAUSE_EN | -+ ASPEED_JTAG_ISR_DATA_COMPLETE_EN, -+ ASPEED_JTAG_ISR); /* Enable Interrupt */ -+} ++ rx_stat = readl(priv->reg_base + CAN_CTRL); + -+static inline void aspeed_jtag_master_26xx(struct aspeed_jtag *aspeed_jtag) -+{ -+ u32 reg_val; ++ while ((rx_stat & CAN_CTRL_RSTAT_NOT_EMPTY_MASKT) != 0 && ++ (work_done < quota)) { ++ work_done += aspeed_can_rx(ndev); ++ rx_stat = readl(priv->reg_base + CAN_CTRL); ++ } + -+ reg_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_GBLCTRL) & -+ ASPEED_JTAG_CLK_DIVISOR_MASK; -+ if (aspeed_jtag->mode & JTAG_XFER_HW_MODE) { -+ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_CTRL); -+ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW); -+ } else { -+ aspeed_jtag_write(aspeed_jtag, -+ ASPEED_JTAG_SW_MODE_EN | -+ ASPEED_JTAG_SW_MODE_TDIO, -+ ASPEED_JTAG_SW); ++ if (work_done) ++ aspeed_can_update_error_state_after_rxtx(ndev); ++ ++ if (work_done < quota) { ++ if (napi_complete_done(napi, work_done)) { ++ ier = readl(priv->reg_base + CAN_INTE); ++ ier |= CAN_INT_RIE_BIT; ++ writel(ier, priv->reg_base + CAN_INTE); ++ } + } -+ /* -+ * For the software mode, it's still necessary to enable out_en and -+ * select the out_en in the hw2 register to maintain control of the -+ * TRST bit same as hw2. -+ */ -+ aspeed_jtag_write(aspeed_jtag, -+ reg_val | ASPEED_JTAG_GBLCTRL_ENG_MODE_EN | -+ ASPEED_JTAG_GBLCTRL_ENG_OUT_EN | -+ ASPEED_JTAG_GBLCTRL_TRST, -+ ASPEED_JTAG_GBLCTRL); -+ aspeed_jtag_write(aspeed_jtag, -+ ASPEED_JTAG_INTCTRL_SHCPL_IRQ_EN | -+ ASPEED_JTAG_INTCTRL_SHCPL_IRQ_STAT, -+ ASPEED_JTAG_INTCTRL); /* Enable HW2 IRQ */ + -+ aspeed_jtag_write(aspeed_jtag, -+ ASPEED_JTAG_ISR_INST_PAUSE | -+ ASPEED_JTAG_ISR_INST_COMPLETE | -+ ASPEED_JTAG_ISR_DATA_PAUSE | -+ ASPEED_JTAG_ISR_DATA_COMPLETE | -+ ASPEED_JTAG_ISR_INST_PAUSE_EN | -+ ASPEED_JTAG_ISR_INST_COMPLETE_EN | -+ ASPEED_JTAG_ISR_DATA_PAUSE_EN | -+ ASPEED_JTAG_ISR_DATA_COMPLETE_EN, -+ ASPEED_JTAG_ISR); /* Enable HW1 Interrupts */ ++ return work_done; +} + -+static int aspeed_jtag_mode_set(struct jtag *jtag, struct jtag_mode *jtag_mode) ++static void aspeed_can_tx_interrupt(struct net_device *ndev, u32 intr_flag) +{ -+ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ struct net_device_stats *stats = &ndev->stats; ++ u32 frames_in_fifo; ++ unsigned long flags; ++ u32 can_ctrl; ++ u32 stauts_2; ++ u32 handle; ++ u32 skb_idx; ++ int ret; + -+ switch (jtag_mode->feature) { -+ case JTAG_XFER_MODE: -+ aspeed_jtag->mode = jtag_mode->mode; -+ aspeed_jtag->llops->master_enable(aspeed_jtag); -+ break; -+ case JTAG_CONTROL_MODE: -+ if (jtag_mode->mode == JTAG_CONTROLLER_OUTPUT_DISABLE) -+ aspeed_jtag->llops->output_disable(aspeed_jtag); -+ else if (jtag_mode->mode == JTAG_CONTROLLER_MODE) -+ aspeed_jtag->llops->master_enable(aspeed_jtag); -+ break; -+ default: -+ return -EINVAL; ++ spin_lock_irqsave(&priv->tx_lock, flags); ++ ++ /* PTB */ ++ if (intr_flag & CAN_INT_TPIF_BIT) { ++ aspeed_can_clr_irq_bits(priv, CAN_INTF, CAN_INT_TPIF_BIT); ++ stats->tx_bytes += can_get_echo_skb(ndev, 0, NULL); ++ goto exit; + } -+ return 0; -+} + -+/* -+ * We read and write from an unused JTAG Master controller register in SW -+ * mode to create a delay in xfers. -+ * We found this mechanism better than any udelay or usleep option. -+ */ -+static inline void aspeed_jtag_sw_delay_26xx(struct aspeed_jtag *aspeed_jtag) -+{ -+ u32 read_reg = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_PADCTRL1); ++ /* STB */ ++ can_ctrl = readl(priv->reg_base + CAN_CTRL); ++ stauts_2 = readl(priv->reg_base + CAN_TSTAT); + -+ aspeed_jtag_write(aspeed_jtag, read_reg, ASPEED_JTAG_PADCTRL1); -+} ++ switch (priv->stb_mode_policy) { ++ case (STB_TX_MODE_ONE | STB_POLICY_PRIO): ++ aspeed_can_clr_irq_bits(priv, CAN_INTF, CAN_INT_TSIF_BIT); + -+static char aspeed_jtag_tck_cycle(struct aspeed_jtag *aspeed_jtag, u8 tms, -+ u8 tdi) -+{ -+ char tdo = 0; ++ handle = (stauts_2 & CAN_TSTAT2_HANDLE_MASK) >> ++ CAN_TSTAT2_HANDLE_BITOFF; ++ skb_idx = aspeed_can_get_skb_idx(ndev, handle); ++ if (skb_idx == STB_INVALID_SKB_IDX) { ++ netdev_err(ndev, "fail to get skb idx (%x)\n", ++ STB_TX_MODE_ONE | STB_POLICY_PRIO); ++ } else { ++ stats->tx_bytes += can_get_echo_skb(ndev, skb_idx, NULL); ++ stats->tx_packets++; ++ ret = aspeed_can_drop_ring_obj(ndev, handle); ++ /* priv->tail_ptr = priv->tail_ptr.next; */ ++ if (ret < 0) { ++ netdev_err(ndev, "fail to drop a ring obj (%x)\n", ++ STB_TX_MODE_ONE | STB_POLICY_PRIO); ++ } ++ } + -+ /* TCK = 0 */ -+ aspeed_jtag_write(aspeed_jtag, -+ ASPEED_JTAG_SW_MODE_EN | -+ (tms * ASPEED_JTAG_SW_MODE_TMS) | -+ (tdi * ASPEED_JTAG_SW_MODE_TDIO), -+ ASPEED_JTAG_SW); ++ /* something still in STB */ ++ if ((can_ctrl & CAN_CTRL_TSSTAT_MASK) != 0x0) ++ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_TSONE_BIT); ++ break; + -+ /* Wait until JTAG Master controller finishes the operation */ -+ if (aspeed_jtag->llops->xfer_sw_delay) -+ aspeed_jtag->llops->xfer_sw_delay(aspeed_jtag); -+ else -+ aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_SW); ++ case (STB_TX_MODE_ALL | STB_POLICY_FIFO): ++ case (STB_TX_MODE_ALL | STB_POLICY_PRIO): + -+ ndelay(aspeed_jtag->tck_period >> 1); ++ aspeed_can_clr_irq_bits(priv, CAN_INTF, CAN_INT_TSIF_BIT); + -+ /* TCK = 1 */ -+ aspeed_jtag_write(aspeed_jtag, -+ ASPEED_JTAG_SW_MODE_EN | ASPEED_JTAG_SW_MODE_TCK | -+ (tms * ASPEED_JTAG_SW_MODE_TMS) | -+ (tdi * ASPEED_JTAG_SW_MODE_TDIO), -+ ASPEED_JTAG_SW); ++ frames_in_fifo = aspeed_can_get_frame_num(ndev); + -+ /* Wait until JTAG Master controller finishes the operation */ -+ if (aspeed_jtag->llops->xfer_sw_delay) -+ aspeed_jtag->llops->xfer_sw_delay(aspeed_jtag); ++ /* Potential situation: A frame is submitted before this ISR. ++ * That new frame waits for transmission. ++ * This frame should be handled in the next ISR. ++ */ ++ if (can_ctrl & CAN_CTRL_TSSTAT_MASK) ++ frames_in_fifo--; + -+ ndelay(aspeed_jtag->tck_period >> 1); ++ while (frames_in_fifo != 0) { ++ stats->tx_bytes += can_get_echo_skb(ndev, ++ priv->tail_ptr->skb_idx, ++ NULL); ++ priv->tail_ptr->handle = STB_INVALID_HANDLE_VAL; ++ priv->tail_ptr = priv->tail_ptr->next; ++ stats->tx_packets++; ++ frames_in_fifo--; ++ } + -+ if (aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_SW) & -+ ASPEED_JTAG_SW_MODE_TDIO) -+ tdo = 1; ++ /* something still in STB */ ++ if (can_ctrl & CAN_CTRL_TSSTAT_MASK) ++ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_TSALL_BIT); + -+ return tdo; -+} ++ break; ++ default: ++ /* including STB_TX_MODE_ONE and STB_POLICY_FIFO mode */ ++ aspeed_can_clr_irq_bits(priv, CAN_INTF, CAN_INT_TSIF_BIT); + -+static int aspeed_jtag_bitbang(struct jtag *jtag, -+ struct bitbang_packet *bitbang, -+ struct tck_bitbang *bitbang_data) -+{ -+ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); -+ int i = 0; ++ stats->tx_bytes += can_get_echo_skb(ndev, ++ priv->tail_ptr->skb_idx, ++ NULL); ++ priv->tail_ptr = priv->tail_ptr->next; ++ stats->tx_packets++; + -+ for (i = 0; i < bitbang->length; i++) { -+ bitbang_data[i].tdo = -+ aspeed_jtag_tck_cycle(aspeed_jtag, bitbang_data[i].tms, -+ bitbang_data[i].tdi); ++ /* something in STB */ ++ if ((can_ctrl & CAN_CTRL_TSSTAT_MASK) != 0x0) ++ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_TSONE_BIT); + } -+ return 0; -+} + -+static inline void aspeed_jtag_xfer_hw_fifo_delay_26xx(void) -+{ -+ udelay(AST26XX_FIFO_UDELAY); ++exit: ++ netif_wake_queue(ndev); ++ ++ spin_unlock_irqrestore(&priv->tx_lock, flags); ++ ++ aspeed_can_update_error_state_after_rxtx(ndev); +} + -+static int aspeed_jtag_isr_wait(struct aspeed_jtag *aspeed_jtag, u32 bit) ++static irqreturn_t aspeed_can_interrupt(int irq, void *dev_id) +{ -+ int res = 0; -+ u32 status = 0; -+ u32 iterations = 0; ++ struct net_device *ndev = (struct net_device *)dev_id; ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ u32 isr; ++ u32 ier; ++ u32 isr_errors; ++ u32 rx_int_mask = CAN_INT_RIF_BIT; + -+ if (!aspeed_jtag->irq) { -+ res = wait_event_interruptible(aspeed_jtag->jtag_wq, -+ aspeed_jtag->flag & bit); -+ aspeed_jtag->flag &= ~bit; -+ } else { -+ while ((status & bit) == 0) { -+ status = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_ISR); -+#ifdef DEBUG_JTAG -+ dev_dbg(aspeed_jtag->dev, "%s = 0x%08x\n", __func__, -+ status); -+#endif -+ iterations++; -+ if (iterations > WAIT_ITERATIONS) { -+ dev_err(aspeed_jtag->dev, -+ "%s %d in ASPEED_JTAG_ISR\n", -+ "aspeed_jtag driver timed out waiting for bit", -+ bit); -+ res = -EFAULT; -+ break; -+ } -+ if ((status & ASPEED_JTAG_ISR_DATA_COMPLETE) == 0) { -+ if (iterations % 25 == 0) -+ usleep_range(1, 5); -+ else -+ udelay(1); -+ } -+ } -+ aspeed_jtag_write(aspeed_jtag, bit | (status & 0xf), -+ ASPEED_JTAG_ISR); ++ isr = readl(priv->reg_base + CAN_INTF); ++ if (!isr) ++ return IRQ_NONE; ++ ++ /* Check for Tx interrupt and Processing it */ ++ if (isr & (CAN_INT_TPIF_BIT | CAN_INT_TSIF_BIT)) ++ aspeed_can_tx_interrupt(ndev, isr); ++ ++ if (isr & CAN_INT_RAFIF_BIT) { ++ netdev_warn(ndev, "Receive buffer is almost full\n"); ++ aspeed_can_clr_irq_bits(priv, CAN_INTF, CAN_INT_RAFIF_BIT); + } -+ return res; -+} + -+static int aspeed_jtag_wait_shift_complete(struct aspeed_jtag *aspeed_jtag) -+{ -+ int res = 0; -+ u32 status = 0; -+ u32 iterations = 0; ++ if (isr & CAN_INT_RFIF_BIT) { ++ netdev_warn(ndev, "Receive buffer is full\n"); ++ aspeed_can_clr_irq_bits(priv, CAN_INTF, CAN_INT_RFIF_BIT); ++ } + -+ if (!aspeed_jtag->irq) { -+ res = wait_event_interruptible(aspeed_jtag->jtag_wq, -+ aspeed_jtag->flag & -+ ASPEED_JTAG_INTCTRL_SHCPL_IRQ_STAT); -+ aspeed_jtag->flag &= ~ASPEED_JTAG_INTCTRL_SHCPL_IRQ_STAT; -+ } else { -+ while ((status & ASPEED_JTAG_INTCTRL_SHCPL_IRQ_STAT) == 0) { -+ status = aspeed_jtag_read(aspeed_jtag, -+ ASPEED_JTAG_INTCTRL); -+#ifdef DEBUG_JTAG -+ dev_dbg(aspeed_jtag->dev, "%s = 0x%08x\n", __func__, -+ status); -+#endif -+ iterations++; -+ if (iterations > WAIT_ITERATIONS) { -+ dev_err(aspeed_jtag->dev, -+ "aspeed_jtag driver timed out waiting for shift completed\n"); -+ res = -EFAULT; -+ break; -+ } -+ if (iterations % 25 == 0) -+ usleep_range(1, 5); -+ else -+ udelay(1); -+ } -+ aspeed_jtag_write(aspeed_jtag, -+ ASPEED_JTAG_INTCTRL_SHCPL_IRQ_STAT | -+ ASPEED_JTAG_INTCTRL_SHCPL_IRQ_EN, -+ ASPEED_JTAG_INTCTRL); ++ /* Check for the type of error interrupt and Processing it */ ++ isr_errors = isr & (CAN_INT_EIF_BIT | CAN_INT_ROIF_BIT | ++ CAN_INT_BEIF_BIT | CAN_INT_ALIF_BIT | ++ CAN_INT_EPIF_BIT | CAN_INT_EWARN_BIT); ++ if (isr_errors) { ++ aspeed_can_clr_irq_bits(priv, CAN_INTF, isr_errors); ++ aspeed_can_err_interrupt(ndev, isr); + } + -+ return res; ++ /* Check for the type of receive interrupt and Processing it */ ++ if (isr & rx_int_mask) { ++ aspeed_can_clr_irq_bits(priv, CAN_INTF, rx_int_mask); ++ ier = readl(priv->reg_base + CAN_INTE); ++ ier &= ~rx_int_mask; /* CAN_INT_RIE_BIT */ ++ writel(ier, priv->reg_base + CAN_INTE); ++ napi_schedule(&priv->napi); ++ } ++ ++ return IRQ_HANDLED; +} + -+static void aspeed_jtag_set_tap_state(struct aspeed_jtag *aspeed_jtag, -+ enum jtag_tapstate from_state, -+ enum jtag_tapstate end_state) ++static void aspeed_can_chip_stop(struct net_device *ndev) +{ -+ int i = 0; -+ enum jtag_tapstate from, to; ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ int ret; + -+ from = from_state; -+ to = end_state; ++ /* Disable interrupts and leave the can in configuration mode */ ++ ret = aspeed_can_set_reset_mode(ndev); ++ if (ret < 0) ++ netdev_dbg(ndev, "aspeed_can_set_reset_mode() Failed\n"); + -+ for (i = 0; i < _tms_cycle_lookup[from][to].count; i++) -+ aspeed_jtag_tck_cycle(aspeed_jtag, -+ ((_tms_cycle_lookup[from][to].tmsbits -+ >> i) & 0x1), 0); -+ aspeed_jtag->current_state = end_state; ++ priv->can.state = CAN_STATE_STOPPED; +} + -+static void aspeed_jtag_set_tap_state_sw(struct aspeed_jtag *aspeed_jtag, -+ struct jtag_tap_state *tapstate) ++static int aspeed_can_open(struct net_device *ndev) +{ -+ int i; ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ int ret; + -+ /* SW mode from curent tap state -> to end_state */ -+ if (tapstate->reset || tapstate->endstate == JTAG_STATE_TLRESET) { -+ for (i = 0; i < ASPEED_JTAG_RESET_CNTR; i++) -+ aspeed_jtag_tck_cycle(aspeed_jtag, 1, 0); -+ aspeed_jtag->current_state = JTAG_STATE_TLRESET; ++ ret = pm_runtime_get_sync(priv->dev); ++ if (ret < 0) { ++ netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n", ++ __func__, ret); ++ goto err; + } + -+ aspeed_jtag_set_tap_state(aspeed_jtag, tapstate->from, -+ tapstate->endstate); -+ if (tapstate->endstate == JTAG_STATE_TLRESET || -+ tapstate->endstate == JTAG_STATE_IDLE || -+ tapstate->endstate == JTAG_STATE_PAUSEDR || -+ tapstate->endstate == JTAG_STATE_PAUSEIR) -+ for (i = 0; i < tapstate->tck; i++) -+ aspeed_jtag_tck_cycle(aspeed_jtag, 0, 0); -+} ++ ret = request_irq(ndev->irq, aspeed_can_interrupt, 0, ++ ndev->name, ndev); ++ if (ret < 0) { ++ netdev_err(ndev, "irq allocation for CAN failed\n"); ++ goto err; ++ } + -+static int aspeed_jtag_status_set(struct jtag *jtag, -+ struct jtag_tap_state *tapstate) -+{ -+ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); -+ int i; ++ /* Set chip into reset mode */ ++ ret = aspeed_can_set_reset_mode(ndev); ++ if (ret < 0) { ++ netdev_err(ndev, "mode resetting failed!\n"); ++ goto err_irq; ++ } + -+ if (tapstate->from == JTAG_STATE_CURRENT) -+ tapstate->from = aspeed_jtag->current_state; -+ if (tapstate->endstate == JTAG_STATE_CURRENT) -+ tapstate->endstate = aspeed_jtag->current_state; -+#ifdef DEBUG_JTAG -+ dev_dbg(aspeed_jtag->dev, "Set TAP state: %s\n", -+ end_status_str[tapstate->endstate]); -+#endif ++ /* Common open */ ++ ret = open_candev(ndev); ++ if (ret) ++ goto err_irq; + -+ if (!(aspeed_jtag->mode & JTAG_XFER_HW_MODE)) { -+ aspeed_jtag_set_tap_state_sw(aspeed_jtag, tapstate); -+ return 0; ++ ret = aspeed_can_chip_start(ndev); ++ if (ret < 0) { ++ netdev_err(ndev, "aspeed_can_chip_start failed!\n"); ++ goto err_candev; + } + -+ /* x TMS high + 1 TMS low */ -+ if (tapstate->reset) { -+ /* Disable sw mode */ -+ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW); -+ mdelay(1); -+ aspeed_jtag_write(aspeed_jtag, -+ ASPEED_JTAG_CTL_ENG_EN | -+ ASPEED_JTAG_CTL_ENG_OUT_EN | -+ ASPEED_JTAG_CTL_FORCE_TMS, -+ ASPEED_JTAG_CTRL); -+ mdelay(1); -+ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_TDIO, -+ ASPEED_JTAG_SW); -+ aspeed_jtag->current_state = JTAG_STATE_TLRESET; -+ } -+ for (i = 0; i < tapstate->tck; i++) -+ ndelay(aspeed_jtag->tck_period); ++ napi_enable(&priv->napi); ++ netif_start_queue(ndev); + + return 0; -+} + -+static int aspeed_jtag_shctrl_tms_mask(enum jtag_tapstate from, -+ enum jtag_tapstate to, -+ enum jtag_tapstate there, -+ enum jtag_tapstate endstate, -+ u32 start_shift, u32 end_shift, -+ u32 *tms_mask) -+{ -+ u32 pre_tms = start_shift ? _tms_cycle_lookup[from][to].count : 0; -+ u32 post_tms = end_shift ? _tms_cycle_lookup[there][endstate].count : 0; -+ u32 tms_value = start_shift ? _tms_cycle_lookup[from][to].tmsbits : 0; ++err_candev: ++ close_candev(ndev); ++err_irq: ++ free_irq(ndev->irq, ndev); ++err: ++ pm_runtime_put(priv->dev); + -+ tms_value |= end_shift ? _tms_cycle_lookup[there][endstate].tmsbits -+ << pre_tms : -+ 0; -+ if (pre_tms > GENMASK(2, 0) || post_tms > GENMASK(2, 0)) { -+ pr_err("pre/port tms count is greater than hw limit"); -+ return -EINVAL; -+ } -+ *tms_mask = start_shift | ASPEED_JTAG_SHCTRL_PRE_TMS(pre_tms) | -+ end_shift | ASPEED_JTAG_SHCTRL_POST_TMS(post_tms) | -+ ASPEED_JTAG_SHCTRL_TMS(tms_value); -+ return 0; ++ return ret; +} + -+static void aspeed_jtag_set_tap_state_hw2(struct aspeed_jtag *aspeed_jtag, -+ struct jtag_tap_state *tapstate) ++static int aspeed_can_close(struct net_device *ndev) +{ -+ u32 reg_val, execute_tck; -+ u32 tck = tapstate->tck; ++ struct aspeed_can_priv *priv = netdev_priv(ndev); + -+ /* x TMS high + 1 TMS low */ -+ if (tapstate->reset || tapstate->endstate == JTAG_STATE_TLRESET) { -+ /* Disable sw mode */ -+ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW); -+ udelay(AST26XX_JTAG_CTRL_UDELAY); -+ reg_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_GBLCTRL); -+ aspeed_jtag_write(aspeed_jtag, -+ reg_val | ASPEED_JTAG_GBLCTRL_ENG_MODE_EN | -+ ASPEED_JTAG_GBLCTRL_ENG_OUT_EN | -+ ASPEED_JTAG_GBLCTRL_RESET_FIFO | -+ ASPEED_JTAG_GBLCTRL_FORCE_TMS, -+ ASPEED_JTAG_GBLCTRL); -+ udelay(AST26XX_JTAG_CTRL_UDELAY); -+ while (aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_GBLCTRL) & ASPEED_JTAG_GBLCTRL_FORCE_TMS) -+ ; -+ aspeed_jtag->current_state = JTAG_STATE_TLRESET; -+ } else { -+ aspeed_jtag_set_tap_state(aspeed_jtag, -+ aspeed_jtag->current_state, -+ tapstate->endstate); -+ } -+ /* Run TCK */ -+ while (tck) { -+ execute_tck = tck > GENMASK(9, 0) ? GENMASK(9, 0) : tck; -+ /* Disable sw mode */ -+ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW); -+ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_PADCTRL0); -+ reg_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_GBLCTRL); -+ reg_val = reg_val & ~(GENMASK(22, 20)); -+ aspeed_jtag_write(aspeed_jtag, -+ reg_val | ASPEED_JTAG_GBLCTRL_FIFO_CTRL_MODE | -+ ASPEED_JTAG_GBLCTRL_STSHIFT(0) | -+ ASPEED_JTAG_GBLCTRL_UPDT_SHIFT(execute_tck), -+ ASPEED_JTAG_GBLCTRL); ++ netif_stop_queue(ndev); ++ napi_disable(&priv->napi); ++ aspeed_can_chip_stop(ndev); ++ free_irq(ndev->irq, ndev); ++ close_candev(ndev); ++ pm_runtime_put(priv->dev); + -+ aspeed_jtag_write(aspeed_jtag, -+ ASPEED_JTAG_SHCTRL_STSHIFT_EN | -+ ASPEED_JTAG_SHCTRL_LWRDT_SHIFT(execute_tck), -+ ASPEED_JTAG_SHCTRL); -+ aspeed_jtag_wait_shift_complete(aspeed_jtag); -+ tck -= execute_tck; -+ } ++ return 0; +} + -+static int aspeed_jtag_status_set_26xx(struct jtag *jtag, -+ struct jtag_tap_state *tapstate) ++static int aspeed_can_get_berr_counter(const struct net_device *ndev, ++ struct can_berr_counter *bec) +{ -+ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); -+ -+ if (tapstate->from == JTAG_STATE_CURRENT) -+ tapstate->from = aspeed_jtag->current_state; -+ if (tapstate->endstate == JTAG_STATE_CURRENT) -+ tapstate->endstate = aspeed_jtag->current_state; -+#ifdef DEBUG_JTAG -+ dev_dbg(aspeed_jtag->dev, "Set TAP state: status %s from %s to %s\n", -+ end_status_str[aspeed_jtag->current_state], -+ end_status_str[tapstate->from], -+ end_status_str[tapstate->endstate]); -+#endif ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ int ret; + -+ if (!(aspeed_jtag->mode & JTAG_XFER_HW_MODE)) { -+ aspeed_jtag_set_tap_state_sw(aspeed_jtag, tapstate); -+ return 0; ++ ret = pm_runtime_get_sync(priv->dev); ++ if (ret < 0) { ++ netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n", ++ __func__, ret); ++ pm_runtime_put(priv->dev); ++ return ret; + } + -+ aspeed_jtag_set_tap_state_hw2(aspeed_jtag, tapstate); ++ bec->rxerr = (readl(priv->reg_base + CAN_ERR_STAT) & ++ CAN_ERR_RECNT_MASK) >> CAN_ERR_RECNT_BITOFF; ++ bec->txerr = (readl(priv->reg_base + CAN_ERR_STAT) & ++ CAN_ERR_TECNT_MASK) >> CAN_ERR_TECNT_BITOFF; ++ ++ pm_runtime_put(priv->dev); ++ + return 0; +} + -+static void aspeed_jtag_xfer_sw(struct aspeed_jtag *aspeed_jtag, -+ struct jtag_xfer *xfer, u32 *data) ++static int aspeed_can_get_auto_tdcv(const struct net_device *ndev, u32 *tdcv) +{ -+ unsigned long remain_xfer = xfer->length; -+ unsigned long shift_bits = 0; -+ unsigned long index = 0; -+ unsigned long tdi; -+ char tdo; ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ u32 reg; + -+#ifdef DEBUG_JTAG -+ dev_dbg(aspeed_jtag->dev, "SW JTAG SHIFT %s, length = %d\n", -+ (xfer->type == JTAG_SIR_XFER) ? "IR" : "DR", xfer->length); -+#endif ++ reg = readl(priv->reg_base + CAN_BITITME); ++ *tdcv = (reg & CAN_TIMING_FD_SSPOFF_MASK) >> CAN_TIMING_FD_SSPOFF_BITOFF; + -+ if (xfer->type == JTAG_SIR_XFER) -+ aspeed_jtag_set_tap_state(aspeed_jtag, xfer->from, -+ JTAG_STATE_SHIFTIR); -+ else -+ aspeed_jtag_set_tap_state(aspeed_jtag, xfer->from, -+ JTAG_STATE_SHIFTDR); ++ return 0; ++} + -+ tdi = ASPEED_JTAG_GET_TDI(xfer->direction, data[index]); -+ data[index] = 0; -+ while (remain_xfer > 1) { -+ tdo = aspeed_jtag_tck_cycle(aspeed_jtag, 0, -+ tdi & ASPEED_JTAG_DATA_MSB); -+ data[index] |= tdo -+ << (shift_bits % ASPEED_JTAG_DATA_CHUNK_SIZE); -+ tdi >>= 1; -+ shift_bits++; -+ remain_xfer--; ++static const struct net_device_ops aspeed_can_netdev_ops = { ++ .ndo_open = aspeed_can_open, ++ .ndo_stop = aspeed_can_close, ++ .ndo_start_xmit = aspeed_can_start_xmit, ++ .ndo_change_mtu = can_change_mtu, ++}; + -+ if (shift_bits % ASPEED_JTAG_DATA_CHUNK_SIZE == 0) { -+ tdo = 0; -+ index++; -+ tdi = ASPEED_JTAG_GET_TDI(xfer->direction, data[index]); -+ data[index] = 0; -+ } -+ } ++static const struct ethtool_ops aspeed_can_ethtool_ops = { ++ .get_ts_info = ethtool_op_get_ts_info, ++}; + -+ if ((xfer->endstate == (xfer->type == JTAG_SIR_XFER ? -+ JTAG_STATE_SHIFTIR : -+ JTAG_STATE_SHIFTDR))) { -+ /* Stay in Shift IR/DR*/ -+ tdo = aspeed_jtag_tck_cycle(aspeed_jtag, 0, -+ tdi & ASPEED_JTAG_DATA_MSB); -+ data[index] |= tdo -+ << (shift_bits % ASPEED_JTAG_DATA_CHUNK_SIZE); -+ } else { -+ /* Goto end state */ -+ tdo = aspeed_jtag_tck_cycle(aspeed_jtag, 1, -+ tdi & ASPEED_JTAG_DATA_MSB); -+ data[index] |= tdo -+ << (shift_bits % ASPEED_JTAG_DATA_CHUNK_SIZE); -+ aspeed_jtag->status = (xfer->type == JTAG_SIR_XFER) ? -+ JTAG_STATE_EXIT1IR : -+ JTAG_STATE_EXIT1DR; -+ aspeed_jtag_set_tap_state(aspeed_jtag, aspeed_jtag->status, -+ xfer->endstate); ++static int __maybe_unused aspeed_can_suspend(struct device *dev) ++{ ++ struct net_device *ndev = dev_get_drvdata(dev); ++ ++ if (netif_running(ndev)) { ++ netif_stop_queue(ndev); ++ netif_device_detach(ndev); ++ aspeed_can_chip_stop(ndev); + } ++ ++ return pm_runtime_force_suspend(dev); +} + -+static int aspeed_jtag_xfer_push_data_26xx(struct aspeed_jtag *aspeed_jtag, -+ enum jtag_xfer_type type, -+ u32 bits_len) ++static int __maybe_unused aspeed_can_resume(struct device *dev) +{ -+ int res = 0; ++ struct net_device *ndev = dev_get_drvdata(dev); ++ int ret; + -+ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_TRANS_LEN(bits_len), -+ ASPEED_JTAG_CTRL); -+ if (type == JTAG_SIR_XFER) { -+ aspeed_jtag_write(aspeed_jtag, -+ ASPEED_JTAG_TRANS_LEN(bits_len) | -+ ASPEED_JTAG_CTL_26XX_INST_EN, -+ ASPEED_JTAG_CTRL); -+ res = aspeed_jtag_isr_wait(aspeed_jtag, -+ ASPEED_JTAG_ISR_INST_PAUSE); -+ } else { -+ aspeed_jtag_write(aspeed_jtag, -+ ASPEED_JTAG_TRANS_LEN(bits_len) | -+ ASPEED_JTAG_CTL_DATA_EN, -+ ASPEED_JTAG_CTRL); -+ res = aspeed_jtag_isr_wait(aspeed_jtag, -+ ASPEED_JTAG_ISR_DATA_PAUSE); ++ ret = pm_runtime_force_resume(dev); ++ if (ret) { ++ dev_err(dev, "pm_runtime_force_resume failed on resume\n"); ++ return ret; + } -+ return res; -+} + -+static int aspeed_jtag_xfer_push_data(struct aspeed_jtag *aspeed_jtag, -+ enum jtag_xfer_type type, u32 bits_len) -+{ -+ int res = 0; ++ if (netif_running(ndev)) { ++ ret = aspeed_can_chip_start(ndev); ++ if (ret) { ++ dev_err(dev, "aspeed_can_chip_start failed on resume\n"); ++ return ret; ++ } + -+ if (type == JTAG_SIR_XFER) { -+ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_IOUT_LEN(bits_len), -+ ASPEED_JTAG_CTRL); -+ aspeed_jtag_write(aspeed_jtag, -+ ASPEED_JTAG_IOUT_LEN(bits_len) | -+ ASPEED_JTAG_CTL_INST_EN, -+ ASPEED_JTAG_CTRL); -+ res = aspeed_jtag_isr_wait(aspeed_jtag, -+ ASPEED_JTAG_ISR_INST_PAUSE); -+ } else { -+ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_DOUT_LEN(bits_len), -+ ASPEED_JTAG_CTRL); -+ aspeed_jtag_write(aspeed_jtag, -+ ASPEED_JTAG_DOUT_LEN(bits_len) | -+ ASPEED_JTAG_CTL_DATA_EN, -+ ASPEED_JTAG_CTRL); -+ res = aspeed_jtag_isr_wait(aspeed_jtag, -+ ASPEED_JTAG_ISR_DATA_PAUSE); ++ netif_device_attach(ndev); ++ netif_start_queue(ndev); + } -+ return res; ++ ++ return 0; +} + -+static int aspeed_jtag_xfer_push_data_last_26xx(struct aspeed_jtag *aspeed_jtag, -+ enum jtag_xfer_type type, -+ u32 shift_bits) ++static int __maybe_unused aspeed_can_runtime_suspend(struct device *dev) +{ -+ int res = 0; ++ struct net_device *ndev = dev_get_drvdata(dev); ++ struct aspeed_can_priv *priv = netdev_priv(ndev); + -+ aspeed_jtag_write(aspeed_jtag, -+ ASPEED_JTAG_TRANS_LEN(shift_bits) | -+ ASPEED_JTAG_CTL_26XX_LASPEED_TRANS, -+ ASPEED_JTAG_CTRL); -+ if (type == JTAG_SIR_XFER) { -+ aspeed_jtag_write(aspeed_jtag, -+ ASPEED_JTAG_TRANS_LEN(shift_bits) | -+ ASPEED_JTAG_CTL_26XX_LASPEED_TRANS | -+ ASPEED_JTAG_CTL_26XX_INST_EN, -+ ASPEED_JTAG_CTRL); -+ res = aspeed_jtag_isr_wait(aspeed_jtag, -+ ASPEED_JTAG_ISR_INST_COMPLETE); -+ } else { -+ aspeed_jtag_write(aspeed_jtag, -+ ASPEED_JTAG_TRANS_LEN(shift_bits) | -+ ASPEED_JTAG_CTL_26XX_LASPEED_TRANS | -+ ASPEED_JTAG_CTL_DATA_EN, -+ ASPEED_JTAG_CTRL); -+ res = aspeed_jtag_isr_wait(aspeed_jtag, -+ ASPEED_JTAG_ISR_DATA_COMPLETE); -+ } -+ return res; ++ clk_disable_unprepare(priv->clk); ++ ++ return 0; +} + -+static int aspeed_jtag_xfer_push_data_last(struct aspeed_jtag *aspeed_jtag, -+ enum jtag_xfer_type type, -+ u32 shift_bits) ++static int __maybe_unused aspeed_can_runtime_resume(struct device *dev) +{ -+ int res = 0; ++ struct net_device *ndev = dev_get_drvdata(dev); ++ struct aspeed_can_priv *priv = netdev_priv(ndev); ++ int ret; + -+ if (type == JTAG_SIR_XFER) { -+ aspeed_jtag_write(aspeed_jtag, -+ ASPEED_JTAG_IOUT_LEN(shift_bits) | -+ ASPEED_JTAG_CTL_LASPEED_INST, -+ ASPEED_JTAG_CTRL); -+ aspeed_jtag_write(aspeed_jtag, -+ ASPEED_JTAG_IOUT_LEN(shift_bits) | -+ ASPEED_JTAG_CTL_LASPEED_INST | -+ ASPEED_JTAG_CTL_INST_EN, -+ ASPEED_JTAG_CTRL); -+ res = aspeed_jtag_isr_wait(aspeed_jtag, -+ ASPEED_JTAG_ISR_INST_COMPLETE); -+ } else { -+ aspeed_jtag_write(aspeed_jtag, -+ ASPEED_JTAG_DOUT_LEN(shift_bits) | -+ ASPEED_JTAG_CTL_LASPEED_DATA, -+ ASPEED_JTAG_CTRL); -+ aspeed_jtag_write(aspeed_jtag, -+ ASPEED_JTAG_DOUT_LEN(shift_bits) | -+ ASPEED_JTAG_CTL_LASPEED_DATA | -+ ASPEED_JTAG_CTL_DATA_EN, -+ ASPEED_JTAG_CTRL); -+ res = aspeed_jtag_isr_wait(aspeed_jtag, -+ ASPEED_JTAG_ISR_DATA_COMPLETE); ++ ret = clk_prepare_enable(priv->clk); ++ if (ret) { ++ dev_err(dev, "Cannot enable clock.\n"); ++ return ret; + } -+ return res; ++ ++ return 0; +} + -+static int aspeed_jtag_xfer_hw(struct aspeed_jtag *aspeed_jtag, -+ struct jtag_xfer *xfer, u32 *data) ++static const struct dev_pm_ops aspeed_can_dev_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(aspeed_can_suspend, aspeed_can_resume) ++ SET_RUNTIME_PM_OPS(aspeed_can_runtime_suspend, aspeed_can_runtime_resume, NULL) ++}; ++ ++/* Match table for OF platform binding */ ++static const struct of_device_id aspeed_can_of_match[] = { ++ { .compatible = "aspeed,canfd", .data = NULL }, ++ { /* end of list */ }, ++}; ++MODULE_DEVICE_TABLE(of, aspeed_can_of_match); ++ ++static int aspeed_can_probe(struct platform_device *pdev) +{ -+ unsigned long remain_xfer = xfer->length; -+ unsigned long index = 0; -+ char shift_bits; -+ u32 data_reg; -+ u32 scan_end; -+ union pad_config padding; -+ int retval = 0; ++ struct net_device *ndev; ++ struct aspeed_can_priv *priv; ++ int ret; ++ /* Fixed to temporarily. */ ++ u32 rx_max = 3; ++ u32 can_clk; + -+ padding.int_value = xfer->padding; ++ ndev = alloc_candev(sizeof(struct aspeed_can_priv), 4); ++ if (!ndev) ++ return -ENOMEM; + -+#ifdef DEBUG_JTAG -+ dev_dbg(aspeed_jtag->dev, "HW JTAG SHIFT %s, length = %d pad = 0x%x\n", -+ (xfer->type == JTAG_SIR_XFER) ? "IR" : "DR", xfer->length, -+ xfer->padding); -+#endif -+ data_reg = xfer->type == JTAG_SIR_XFER ? ASPEED_JTAG_INST : -+ ASPEED_JTAG_DATA; -+ if (xfer->endstate == JTAG_STATE_SHIFTIR || -+ xfer->endstate == JTAG_STATE_SHIFTDR || -+ xfer->endstate == JTAG_STATE_PAUSEIR || -+ xfer->endstate == JTAG_STATE_PAUSEDR) { -+ scan_end = 0; -+ } else { -+ if (padding.post_pad_number) -+ scan_end = 0; -+ else -+ scan_end = 1; -+ } ++ priv = netdev_priv(ndev); + -+ /* Perform pre padding */ -+ if (padding.pre_pad_number) { -+ struct jtag_xfer pre_xfer = { -+ .type = xfer->type, -+ .direction = JTAG_WRITE_XFER, -+ .from = xfer->from, -+ .endstate = xfer->type == JTAG_SIR_XFER ? -+ JTAG_STATE_SHIFTIR : JTAG_STATE_SHIFTDR, -+ .padding = 0, -+ .length = padding.pre_pad_number, -+ }; -+ if (padding.pre_pad_number > ASPEED_JTAG_MAX_PAD_SIZE) -+ return -EINVAL; -+ retval = aspeed_jtag_xfer_hw(aspeed_jtag, &pre_xfer, -+ padding.pad_data ? -+ aspeed_jtag->pad_data_one : -+ aspeed_jtag->pad_data_zero); -+ if (retval) -+ return retval; -+ } ++ priv->dev = &pdev->dev; ++ priv->reg_base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(priv->reg_base)) { ++ ret = PTR_ERR(priv->reg_base); ++ goto err; ++ }; + -+ while (remain_xfer) { -+ if (xfer->direction & JTAG_WRITE_XFER) -+ aspeed_jtag_write(aspeed_jtag, data[index], data_reg); -+ else -+ aspeed_jtag_write(aspeed_jtag, 0, data_reg); -+ if (aspeed_jtag->llops->xfer_hw_fifo_delay) -+ aspeed_jtag->llops->xfer_hw_fifo_delay(); ++ priv->can.bittiming_const = &aspeed_can_bittiming_const; ++ priv->can.data_bittiming_const = &aspeed_canfd_bittiming_const; ++ priv->can.do_set_mode = aspeed_can_do_set_mode; ++ priv->can.do_get_berr_counter = aspeed_can_get_berr_counter; ++ priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | ++ CAN_CTRLMODE_BERR_REPORTING | ++ CAN_CTRLMODE_FD | ++ CAN_CTRLMODE_CC_LEN8_DLC | ++ CAN_CTRLMODE_TDC_AUTO; ++ priv->can.do_get_auto_tdcv = aspeed_can_get_auto_tdcv; + -+ if (remain_xfer > ASPEED_JTAG_DATA_CHUNK_SIZE) { -+#ifdef DEBUG_JTAG -+ dev_dbg(aspeed_jtag->dev, -+ "Chunk len=%d chunk_size=%d remain_xfer=%lu\n", -+ xfer->length, ASPEED_JTAG_DATA_CHUNK_SIZE, -+ remain_xfer); -+#endif -+ shift_bits = ASPEED_JTAG_DATA_CHUNK_SIZE; ++ priv->tx_max = 3; ++ spin_lock_init(&priv->tx_lock); + -+ /* -+ * Transmit bytes that were not equals to column length -+ * and after the transfer go to Pause IR/DR. -+ */ -+ if (aspeed_jtag->llops->xfer_push_data(aspeed_jtag, -+ xfer->type, -+ shift_bits) -+ != 0) { -+ return -EFAULT; -+ } -+ } else { -+ /* -+ * Read bytes equals to column length -+ */ -+ shift_bits = remain_xfer; -+ if (scan_end) { -+ /* -+ * If this data is the end of the transmission -+ * send remaining bits and go to endstate -+ */ -+#ifdef DEBUG_JTAG -+ dev_dbg(aspeed_jtag->dev, -+ "Last len=%d chunk_size=%d remain_xfer=%lu\n", -+ xfer->length, -+ ASPEED_JTAG_DATA_CHUNK_SIZE, -+ remain_xfer); -+#endif -+ if (aspeed_jtag->llops->xfer_push_data_last( -+ aspeed_jtag, xfer->type, -+ shift_bits) != 0) { -+ return -EFAULT; -+ } -+ } else { -+ /* -+ * If transmission is waiting for additional -+ * data send remaining bits and then go to -+ * Pause IR/DR. -+ */ -+#ifdef DEBUG_JTAG -+ dev_dbg(aspeed_jtag->dev, -+ "Tail len=%d chunk_size=%d remain_xfer=%lu\n", -+ xfer->length, -+ ASPEED_JTAG_DATA_CHUNK_SIZE, -+ remain_xfer); -+#endif -+ if (aspeed_jtag->llops->xfer_push_data( -+ aspeed_jtag, xfer->type, -+ shift_bits) != 0) { -+ return -EFAULT; -+ } -+ } -+ } ++ /* Get IRQ for the device */ ++ ret = platform_get_irq(pdev, 0); ++ if (ret < 0) ++ goto err_free; + -+ if (xfer->direction & JTAG_READ_XFER) { -+ if (shift_bits < ASPEED_JTAG_DATA_CHUNK_SIZE) { -+ data[index] = -+ aspeed_jtag_read(aspeed_jtag, data_reg); ++ ndev->irq = ret; + -+ data[index] >>= ASPEED_JTAG_DATA_CHUNK_SIZE - -+ shift_bits; -+ } else { -+ data[index] = -+ aspeed_jtag_read(aspeed_jtag, data_reg); -+ } -+ if (aspeed_jtag->llops->xfer_hw_fifo_delay) -+ aspeed_jtag->llops->xfer_hw_fifo_delay(); -+ } ++ /* We support local echo */ ++ ndev->flags |= IFF_ECHO; + -+ remain_xfer = remain_xfer - shift_bits; -+ index++; -+ } ++ platform_set_drvdata(pdev, ndev); ++ SET_NETDEV_DEV(ndev, &pdev->dev); ++ ndev->netdev_ops = &aspeed_can_netdev_ops; ++ ndev->ethtool_ops = &aspeed_can_ethtool_ops; + -+ /* Perform post padding */ -+ if (padding.post_pad_number) { -+ struct jtag_xfer post_xfer = { -+ .type = xfer->type, -+ .direction = JTAG_WRITE_XFER, -+ .from = xfer->from, -+ .endstate = xfer->endstate, -+ .padding = 0, -+ .length = padding.post_pad_number, -+ }; -+ if (padding.post_pad_number > ASPEED_JTAG_MAX_PAD_SIZE) -+ return -EINVAL; -+ retval = aspeed_jtag_xfer_hw(aspeed_jtag, &post_xfer, -+ padding.pad_data ? -+ aspeed_jtag->pad_data_one : -+ aspeed_jtag->pad_data_zero); -+ if (retval) -+ return retval; -+ } -+ return 0; -+} -+ -+static int aspeed_jtag_xfer(struct jtag *jtag, struct jtag_xfer *xfer, -+ u8 *xfer_data) -+{ -+ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); -+ -+ if (!(aspeed_jtag->mode & JTAG_XFER_HW_MODE)) { -+ /* SW mode */ -+ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_TDIO, -+ ASPEED_JTAG_SW); -+ -+ aspeed_jtag->llops->xfer_sw(aspeed_jtag, xfer, -+ (u32 *)xfer_data); -+ } else { -+ /* HW mode */ -+ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW); -+ if (aspeed_jtag->llops->xfer_hw(aspeed_jtag, xfer, -+ (u32 *)xfer_data) != 0) -+ return -EFAULT; -+ } -+ -+ aspeed_jtag->status = xfer->endstate; -+ return 0; -+} -+ -+static int aspeed_jtag_xfer_hw2(struct aspeed_jtag *aspeed_jtag, -+ struct jtag_xfer *xfer, u32 *data) -+{ -+ unsigned long remain_xfer = xfer->length; -+ unsigned long partial_xfer_size = 0; -+ unsigned long index = 0; -+ u32 shift_bits; -+ u32 data_reg; -+ u32 reg_val; -+ enum jtag_tapstate shift; -+ enum jtag_tapstate exit; -+ enum jtag_tapstate exitx; -+ enum jtag_tapstate pause; -+ enum jtag_tapstate endstate; -+ u32 start_shift; -+ u32 end_shift; -+ u32 tms_mask; -+ int ret; -+ -+ if (xfer->type == JTAG_SIR_XFER) { -+ data_reg = ASPEED_JTAG_SHDATA; -+ shift = JTAG_STATE_SHIFTIR; -+ pause = JTAG_STATE_PAUSEIR; -+ exit = JTAG_STATE_EXIT1IR; -+ exitx = JTAG_STATE_EXIT1DR; -+ } else { -+ data_reg = ASPEED_JTAG_SHDATA; -+ shift = JTAG_STATE_SHIFTDR; -+ pause = JTAG_STATE_PAUSEDR; -+ exit = JTAG_STATE_EXIT1DR; -+ exitx = JTAG_STATE_EXIT1IR; ++ /* Getting the CAN can_clk info */ ++ priv->clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(priv->clk)) { ++ dev_err(&pdev->dev, "missing clock\n"); ++ return PTR_ERR(priv->clk); + } -+#ifdef DEBUG_JTAG -+ dev_dbg(aspeed_jtag->dev, -+ "HW2 JTAG SHIFT %s, length %d status %s from %s to %s then %s pad 0x%x\n", -+ (xfer->type == JTAG_SIR_XFER) ? "IR" : "DR", xfer->length, -+ end_status_str[aspeed_jtag->current_state], -+ end_status_str[xfer->from], -+ end_status_str[shift], -+ end_status_str[xfer->endstate], xfer->padding); -+#endif + -+ if (aspeed_jtag->current_state == shift) { -+ start_shift = 0; -+ } else { -+ start_shift = ASPEED_JTAG_SHCTRL_START_SHIFT; ++ can_clk = clk_get_rate(priv->clk); ++ if (!can_clk) { ++ dev_err(&pdev->dev, "invalid clock\n"); ++ return -EINVAL; + } + -+ if (xfer->endstate == shift) { -+ /* -+ * In the case of shifting 1 bit of data and attempting to stay -+ * in the SHIFT state, the AST2600 JTAG Master Controller in -+ * Hardware mode 2 has been observed to go to EXIT1 IR/DR -+ * instead of staying in the SHIFT IR/DR state. The following -+ * code special cases this one bit shift and directs the state -+ * machine to go to the PAUSE IR/DR state instead. -+ * Alternatively, the application making driver calls can avoid -+ * this situation as follows: -+ * 1.) Bundle all of the shift bits together into one call -+ * AND/OR -+ * 2.) Direct all partial shifts to move to the PAUSE-IR/DR -+ * state. -+ */ -+ if (xfer->length == 1) { -+#ifdef DEBUG_JTAG -+ dev_warn(aspeed_jtag->dev, "JTAG Silicon WA: going to pause instead of shift"); -+#endif -+ end_shift = ASPEED_JTAG_SHCTRL_END_SHIFT; -+ endstate = pause; -+ } else { -+ end_shift = 0; -+ endstate = shift; -+ } -+ } else { -+ endstate = xfer->endstate; -+ end_shift = ASPEED_JTAG_SHCTRL_END_SHIFT; ++ ret = clk_prepare_enable(priv->clk); ++ if (ret) { ++ dev_err(&pdev->dev, "can not enable the clock\n"); ++ return ret; + } + -+ aspeed_jtag_write(aspeed_jtag, xfer->padding, ASPEED_JTAG_PADCTRL0); -+ -+ while (remain_xfer) { -+ unsigned long partial_xfer; -+ unsigned long partial_index; -+ -+ if (remain_xfer > ASPEED_JTAG_HW2_DATA_CHUNK_SIZE) -+ partial_xfer_size = ASPEED_JTAG_HW2_DATA_CHUNK_SIZE; -+ else -+ partial_xfer_size = remain_xfer; -+ -+ partial_index = index; -+ partial_xfer = partial_xfer_size; -+ -+ reg_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_GBLCTRL); -+ 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); -+ -+ while (partial_xfer) { -+ if (partial_xfer > ASPEED_JTAG_DATA_CHUNK_SIZE) -+ shift_bits = ASPEED_JTAG_DATA_CHUNK_SIZE; -+ else -+ shift_bits = partial_xfer; -+ -+ if (xfer->direction & JTAG_WRITE_XFER) -+ aspeed_jtag_write(aspeed_jtag, -+ data[partial_index++], -+ data_reg); -+ else -+ aspeed_jtag_write(aspeed_jtag, 0, data_reg); -+ if (aspeed_jtag->llops->xfer_hw_fifo_delay) -+ aspeed_jtag->llops->xfer_hw_fifo_delay(); -+ partial_xfer = partial_xfer - shift_bits; -+ } -+ if (remain_xfer > ASPEED_JTAG_HW2_DATA_CHUNK_SIZE) { -+ shift_bits = ASPEED_JTAG_HW2_DATA_CHUNK_SIZE; -+ -+ /* -+ * Transmit bytes that were not equals to column length -+ * and after the transfer go to Pause IR/DR. -+ */ ++ priv->can.clock.freq = can_clk; + -+ ret = aspeed_jtag_shctrl_tms_mask(aspeed_jtag->current_state, shift, exit, -+ endstate, start_shift, 0, &tms_mask); -+ if (ret) -+ return ret; ++ priv->tb_mode = PTB_MODE; ++ if (of_property_read_bool(priv->dev->of_node, "can-stb-mode")) ++ priv->tb_mode = STB_MODE; + -+ reg_val = aspeed_jtag_read(aspeed_jtag, -+ ASPEED_JTAG_GBLCTRL); -+ reg_val = reg_val & ~(GENMASK(22, 20)); -+ aspeed_jtag_write(aspeed_jtag, reg_val | -+ ASPEED_JTAG_GBLCTRL_FIFO_CTRL_MODE | -+ ASPEED_JTAG_GBLCTRL_UPDT_SHIFT( -+ shift_bits), -+ ASPEED_JTAG_GBLCTRL); ++ priv->stb_mode_policy = STB_TX_MODE_ONE; ++ if (of_property_read_bool(priv->dev->of_node, "can-stb-tx-all")) ++ priv->stb_mode_policy = STB_TX_MODE_ALL; + -+ aspeed_jtag_write(aspeed_jtag, tms_mask | -+ ASPEED_JTAG_SHCTRL_LWRDT_SHIFT(shift_bits), -+ ASPEED_JTAG_SHCTRL); -+ aspeed_jtag_wait_shift_complete(aspeed_jtag); -+ } else { -+ /* -+ * Read bytes equals to column length -+ */ -+ shift_bits = remain_xfer; -+ ret = aspeed_jtag_shctrl_tms_mask(aspeed_jtag->current_state, shift, exit, -+ endstate, start_shift, end_shift, -+ &tms_mask); -+ if (ret) -+ return ret; ++ if (of_property_read_bool(priv->dev->of_node, "can-stb-priority")) ++ priv->stb_mode_policy |= STB_POLICY_PRIO; ++ else ++ priv->stb_mode_policy |= STB_POLICY_FIFO; + -+ reg_val = aspeed_jtag_read(aspeed_jtag, -+ ASPEED_JTAG_GBLCTRL); -+ reg_val = reg_val & ~(GENMASK(22, 20)); -+ aspeed_jtag_write(aspeed_jtag, reg_val | -+ ASPEED_JTAG_GBLCTRL_FIFO_CTRL_MODE | -+ ASPEED_JTAG_GBLCTRL_UPDT_SHIFT( -+ shift_bits), -+ ASPEED_JTAG_GBLCTRL); ++ priv->stb_ring = kzalloc(sizeof(*priv->stb_ring) * ++ STB_IDX_RING_SZ, GFP_KERNEL); ++ aspeed_can_stb_ring_obj_init(ndev); + -+ aspeed_jtag_write(aspeed_jtag, tms_mask | -+ ASPEED_JTAG_SHCTRL_LWRDT_SHIFT( -+ shift_bits), -+ ASPEED_JTAG_SHCTRL); ++ if (of_property_read_bool(priv->dev->of_node, "can-internal-loopback")) ++ priv->flag |= ASPEED_CAN_INTERNEL_LOOPBACK; + -+ aspeed_jtag_wait_shift_complete(aspeed_jtag); -+ } ++ priv->reset = devm_reset_control_get_exclusive(&pdev->dev, NULL); ++ if (IS_ERR(priv->reset)) ++ return PTR_ERR(priv->reset); + -+ partial_index = index; -+ partial_xfer = partial_xfer_size; -+ while (partial_xfer) { -+ if (partial_xfer > -+ ASPEED_JTAG_DATA_CHUNK_SIZE) { -+ shift_bits = -+ ASPEED_JTAG_DATA_CHUNK_SIZE; -+ data[partial_index++] = -+ aspeed_jtag_read(aspeed_jtag, -+ data_reg); ++ reset_control_deassert(priv->reset); + -+ } else { -+ shift_bits = partial_xfer; -+ data[partial_index++] = -+ aspeed_jtag_read(aspeed_jtag, -+ data_reg); -+ } -+ if (aspeed_jtag->llops->xfer_hw_fifo_delay) -+ aspeed_jtag->llops->xfer_hw_fifo_delay(); -+ partial_xfer = partial_xfer - shift_bits; -+ } ++ ret = aspeed_can_set_reset_mode(ndev); ++ if (ret < 0) ++ goto err; + -+ remain_xfer = remain_xfer - partial_xfer_size; -+ index = partial_index; -+ start_shift = 0; ++ pm_runtime_enable(&pdev->dev); ++ ret = pm_runtime_get_sync(&pdev->dev); ++ if (ret < 0) { ++ netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n", ++ __func__, ret); ++ goto err_disableclks; + } -+ aspeed_jtag->current_state = endstate; -+ return 0; -+} -+ -+static int aspeed_jtag_status_get(struct jtag *jtag, u32 *status) -+{ -+ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); -+ -+ *status = aspeed_jtag->current_state; -+ return 0; -+} -+ -+static irqreturn_t aspeed_jtag_interrupt(s32 this_irq, void *dev_id) -+{ -+ struct aspeed_jtag *aspeed_jtag = dev_id; -+ irqreturn_t ret; -+ u32 status; + -+ status = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_ISR); ++ netif_napi_add_weight(ndev, &priv->napi, aspeed_can_rx_poll, rx_max); + -+ if (status & ASPEED_JTAG_ISR_INT_MASK) { -+ aspeed_jtag_write(aspeed_jtag, -+ (status & ASPEED_JTAG_ISR_INT_MASK) | -+ (status & -+ ASPEED_JTAG_ISR_INT_EN_MASK), -+ ASPEED_JTAG_ISR); -+ aspeed_jtag->flag |= status & ASPEED_JTAG_ISR_INT_MASK; ++ ret = register_candev(ndev); ++ if (ret) { ++ dev_err(&pdev->dev, "fail to register failed (err=%d)\n", ret); ++ goto err_disableclks; + } + -+ if (aspeed_jtag->flag) { -+ wake_up_interruptible(&aspeed_jtag->jtag_wq); -+ ret = IRQ_HANDLED; -+ } else { -+ dev_err(aspeed_jtag->dev, "irq status:%x\n", status); -+ ret = IRQ_NONE; -+ } -+ return ret; -+} ++ pm_runtime_put(&pdev->dev); + -+static irqreturn_t aspeed_jtag_interrupt_hw2(s32 this_irq, void *dev_id) -+{ -+ struct aspeed_jtag *aspeed_jtag = dev_id; -+ irqreturn_t ret; -+ u32 status; ++ netdev_dbg(ndev, "reg_base = 0x%p, irq = %d, clock = %d\n", ++ priv->reg_base, ndev->irq, priv->can.clock.freq); + -+ status = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_INTCTRL); ++ return 0; + -+ if (status & ASPEED_JTAG_INTCTRL_SHCPL_IRQ_STAT) { -+ aspeed_jtag_write(aspeed_jtag, -+ status | ASPEED_JTAG_INTCTRL_SHCPL_IRQ_STAT, -+ ASPEED_JTAG_INTCTRL); -+ aspeed_jtag->flag |= status & ASPEED_JTAG_INTCTRL_SHCPL_IRQ_STAT; -+ } ++err_disableclks: ++ pm_runtime_put(priv->dev); ++ pm_runtime_disable(&pdev->dev); ++err_free: ++ free_candev(ndev); ++err: ++ kfree(priv->stb_ring); + -+ if (aspeed_jtag->flag) { -+ wake_up_interruptible(&aspeed_jtag->jtag_wq); -+ ret = IRQ_HANDLED; -+ } else { -+ dev_err(aspeed_jtag->dev, "irq status:%x\n", status); -+ ret = IRQ_NONE; -+ } + return ret; +} + -+static int aspeed_jtag_enable(struct jtag *jtag) ++static void aspeed_can_remove(struct platform_device *pdev) +{ -+ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); -+ -+ aspeed_jtag->llops->master_enable(aspeed_jtag); -+ return 0; -+} ++ struct net_device *ndev = platform_get_drvdata(pdev); ++ struct aspeed_can_priv *priv = netdev_priv(ndev); + -+static int aspeed_jtag_disable(struct jtag *jtag) -+{ -+ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); ++ reset_control_assert(priv->reset); ++ unregister_candev(ndev); ++ pm_runtime_disable(&pdev->dev); ++ kfree(priv->stb_ring); + -+ aspeed_jtag->llops->output_disable(aspeed_jtag); -+ return 0; ++ free_candev(ndev); +} + -+static int aspeed_jtag_init(struct platform_device *pdev, -+ struct aspeed_jtag *aspeed_jtag) -+{ -+ struct resource *res; -+ -+ memset(aspeed_jtag->pad_data_one, ~0, -+ sizeof(aspeed_jtag->pad_data_one)); -+ memset(aspeed_jtag->pad_data_zero, 0, -+ sizeof(aspeed_jtag->pad_data_zero)); -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ aspeed_jtag->reg_base = devm_ioremap_resource(aspeed_jtag->dev, res); -+ if (IS_ERR(aspeed_jtag->reg_base)) -+ return -ENOMEM; -+ -+ aspeed_jtag->pclk = devm_clk_get(aspeed_jtag->dev, NULL); -+ if (IS_ERR(aspeed_jtag->pclk)) { -+ dev_err(aspeed_jtag->dev, "devm_clk_get failed\n"); -+ return PTR_ERR(aspeed_jtag->pclk); -+ } ++static struct platform_driver aspeed_can_driver = { ++ .probe = aspeed_can_probe, ++ .remove = aspeed_can_remove, ++ .driver = { ++ .name = DRIVER_NAME, ++ .pm = &aspeed_can_dev_pm_ops, ++ .of_match_table = aspeed_can_of_match, ++ }, ++}; + -+ aspeed_jtag->irq = platform_get_irq(pdev, 0); -+ if (aspeed_jtag->irq < 0) -+ dev_warn(aspeed_jtag->dev, -+ "no irq specified, using polling mode"); ++module_platform_driver(aspeed_can_driver); + -+ if (clk_prepare_enable(aspeed_jtag->pclk)) { -+ dev_err(aspeed_jtag->dev, "no irq specified\n"); -+ return -ENOENT; -+ } ++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; + -+ aspeed_jtag->rst = devm_reset_control_get_shared(&pdev->dev, NULL); -+ if (IS_ERR(aspeed_jtag->rst)) { -+ dev_err(aspeed_jtag->dev, -+ "missing or invalid reset controller device tree entry"); -+ return PTR_ERR(aspeed_jtag->rst); -+ } -+ reset_control_deassert(aspeed_jtag->rst); ++ /* 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; + -+ if (aspeed_jtag->irq >= 0) { -+ aspeed_jtag->irq = -+ devm_request_irq(aspeed_jtag->dev, aspeed_jtag->irq, -+ aspeed_jtag->llops->jtag_interrupt, 0, -+ "aspeed-jtag", aspeed_jtag); -+ if (aspeed_jtag->irq) { -+ dev_warn(aspeed_jtag->dev, -+ "unable to request IRQ, using polling mode"); ++ 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; + } + } + -+ aspeed_jtag->llops->output_disable(aspeed_jtag); -+ -+ aspeed_jtag->flag = 0; -+ aspeed_jtag->mode = 0; -+ init_waitqueue_head(&aspeed_jtag->jtag_wq); -+ return 0; -+} -+ -+static int aspeed_jtag_deinit(struct platform_device *pdev, -+ struct aspeed_jtag *aspeed_jtag) -+{ -+ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_ISR); -+ /* Disable clock */ -+ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_CTRL); -+ reset_control_assert(aspeed_jtag->rst); -+ clk_disable_unprepare(aspeed_jtag->pclk); -+ return 0; -+} -+ -+static int aspeed_jtag_trst_set_hw1(struct aspeed_jtag *aspeed_jtag, u32 active) -+{ -+ aspeed_jtag_write(aspeed_jtag, active ? 0 : ASPEED_JTAG_EC_TRSTn_HIGH, -+ ASPEED_JTAG_EC); -+ return 0; -+} -+ -+static int aspeed_jtag_trst_set_hw2(struct aspeed_jtag *aspeed_jtag, u32 active) -+{ -+ u32 reg_val; + 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; + -+ reg_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_GBLCTRL); -+ if (active) -+ reg_val |= ASPEED_JTAG_GBLCTRL_TRST; -+ else -+ reg_val &= ~ASPEED_JTAG_GBLCTRL_TRST; -+ aspeed_jtag_write(aspeed_jtag, reg_val, ASPEED_JTAG_GBLCTRL); -+ return 0; -+} + /* 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); + -+static int aspeed_jtag_trst_set(struct jtag *jtag, u32 active) -+{ -+ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag); + 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; + -+ return aspeed_jtag->llops->trst_set(aspeed_jtag, active); -+} ++ 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); + -+static const struct jtag_ops aspeed_jtag_ops = { -+ .freq_get = aspeed_jtag_freq_get, -+ .freq_set = aspeed_jtag_freq_set, -+ .status_get = aspeed_jtag_status_get, -+ .status_set = aspeed_jtag_status_set, -+ .xfer = aspeed_jtag_xfer, -+ .mode_set = aspeed_jtag_mode_set, -+ .bitbang = aspeed_jtag_bitbang, -+ .enable = aspeed_jtag_enable, -+ .disable = aspeed_jtag_disable -+}; ++ 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; ++ } ++ } ++ } ++ } + -+static const struct jtag_ops aspeed_jtag_ops_26xx = { -+#ifdef ASPEED_JTAG_HW_MODE_2_ENABLE -+ .freq_get = aspeed_jtag_freq_get_26xx, -+ .freq_set = aspeed_jtag_freq_set_26xx, -+ .status_get = aspeed_jtag_status_get, -+ .status_set = aspeed_jtag_status_set_26xx, -+#else -+ .freq_get = aspeed_jtag_freq_get, -+ .freq_set = aspeed_jtag_freq_set, -+ .status_get = aspeed_jtag_status_get, -+ .status_set = aspeed_jtag_status_set, -+#endif -+ .xfer = aspeed_jtag_xfer, -+ .mode_set = aspeed_jtag_mode_set, -+ .trst_set = aspeed_jtag_trst_set, -+ .bitbang = aspeed_jtag_bitbang, -+ .enable = aspeed_jtag_enable, -+ .disable = aspeed_jtag_disable -+}; ++ 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; ++ } + -+static const struct jtag_low_level_functions ast25xx_llops = { -+ .master_enable = aspeed_jtag_master, -+ .output_disable = aspeed_jtag_output_disable, -+ .xfer_push_data = aspeed_jtag_xfer_push_data, -+ .xfer_push_data_last = aspeed_jtag_xfer_push_data_last, -+ .xfer_sw = aspeed_jtag_xfer_sw, -+ .xfer_hw = aspeed_jtag_xfer_hw, -+ .xfer_hw_fifo_delay = NULL, -+ .xfer_sw_delay = NULL, -+ .jtag_interrupt = aspeed_jtag_interrupt, -+ .trst_set = aspeed_jtag_trst_set_hw1 ++ 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, +}; + -+static const struct aspeed_jtag_functions ast25xx_functions = { -+ .aspeed_jtag_ops = &aspeed_jtag_ops, -+ .aspeed_jtag_llops = &ast25xx_llops ++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 +}; + -+static const struct jtag_low_level_functions ast26xx_llops = { -+#ifdef ASPEED_JTAG_HW_MODE_2_ENABLE -+ .master_enable = aspeed_jtag_master_26xx, -+ .output_disable = aspeed_jtag_output_disable_26xx, -+ .xfer_push_data = aspeed_jtag_xfer_push_data_26xx, -+ .xfer_push_data_last = aspeed_jtag_xfer_push_data_last_26xx, -+ .xfer_sw = aspeed_jtag_xfer_sw, -+ .xfer_hw = aspeed_jtag_xfer_hw2, -+ .xfer_hw_fifo_delay = aspeed_jtag_xfer_hw_fifo_delay_26xx, -+ .xfer_sw_delay = aspeed_jtag_sw_delay_26xx, -+ .jtag_interrupt = aspeed_jtag_interrupt_hw2, -+ .trst_set = aspeed_jtag_trst_set_hw2 -+#else -+ .master_enable = aspeed_jtag_master, -+ .output_disable = aspeed_jtag_output_disable, -+ .xfer_push_data = aspeed_jtag_xfer_push_data_26xx, -+ .xfer_push_data_last = aspeed_jtag_xfer_push_data_last_26xx, -+ .xfer_sw = aspeed_jtag_xfer_sw, -+ .xfer_hw = aspeed_jtag_xfer_hw, -+ .xfer_hw_fifo_delay = aspeed_jtag_xfer_hw_fifo_delay_26xx, -+ .xfer_sw_delay = aspeed_jtag_sw_delay_26xx, -+ .jtag_interrupt = aspeed_jtag_interrupt, -+ .trst_set = aspeed_jtag_trst_set_hw1 -+#endif ++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; +}; + -+static const struct aspeed_jtag_functions ast26xx_functions = { -+ .aspeed_jtag_ops = &aspeed_jtag_ops_26xx, -+ .aspeed_jtag_llops = &ast26xx_llops ++struct mctp_pcie_vdm_dev { ++ struct device *dev; ++ const struct mctp_pcie_vdm_ops *callback_ops; +}; + -+static const struct of_device_id aspeed_jtag_of_match[] = { -+ { .compatible = "aspeed,ast2400-jtag", .data = &ast25xx_functions }, -+ { .compatible = "aspeed,ast2500-jtag", .data = &ast25xx_functions }, -+ { .compatible = "aspeed,ast2600-jtag", .data = &ast26xx_functions }, -+ { .compatible = "aspeed,ast2700-jtag", .data = &ast26xx_functions }, -+ {} ++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 int aspeed_jtag_probe(struct platform_device *pdev) ++static void mctp_pcie_vdm_display_skb_buff_data(struct sk_buff *skb) +{ -+ struct aspeed_jtag *aspeed_jtag; -+ struct jtag *jtag; -+ const struct of_device_id *match; -+ const struct aspeed_jtag_functions *jtag_functions; -+ int err; ++ int i = 0; + -+ match = of_match_node(aspeed_jtag_of_match, pdev->dev.of_node); -+ if (!match) -+ return -ENODEV; -+ jtag_functions = match->data; ++ 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; ++ } + -+ jtag = jtag_alloc(&pdev->dev, sizeof(*aspeed_jtag), -+ jtag_functions->aspeed_jtag_ops); -+ if (!jtag) -+ return -ENOMEM; ++ char buf[16] = { 0 }; ++ char *p = buf; + -+ platform_set_drvdata(pdev, jtag); -+ aspeed_jtag = jtag_priv(jtag); -+ aspeed_jtag->dev = &pdev->dev; ++ while (i < skb->len) { ++ p += snprintf(p, sizeof(buf) - (p - buf), "%02x ", ++ skb->data[i]); ++ i++; ++ } ++ pr_debug("%s\n", buf); ++} + -+ aspeed_jtag->llops = jtag_functions->aspeed_jtag_llops; -+ -+ /* Initialize device*/ -+ err = aspeed_jtag_init(pdev, aspeed_jtag); -+ if (err) -+ goto err_jtag_init; ++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; + -+ /* Initialize JTAG core structure*/ -+ err = devm_jtag_register(aspeed_jtag->dev, jtag); -+ if (err) -+ goto err_jtag_register; ++ 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; + -+ jtag_functions->aspeed_jtag_ops->freq_set(jtag, 1000000); ++ 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)); + -+ return 0; ++ 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)); + -+err_jtag_register: -+ aspeed_jtag_deinit(pdev, aspeed_jtag); -+err_jtag_init: -+ jtag_free(jtag); -+ return err; ++ 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 void aspeed_jtag_remove(struct platform_device *pdev) ++static netdev_tx_t mctp_pcie_vdm_start_xmit(struct sk_buff *skb, ++ struct net_device *ndev) +{ -+ struct jtag *jtag = platform_get_drvdata(pdev); -+ -+ aspeed_jtag_deinit(pdev, jtag_priv(jtag)); -+} -+ -+static struct platform_driver aspeed_jtag_driver = { -+ .probe = aspeed_jtag_probe, -+ .remove = aspeed_jtag_remove, -+ .driver = { -+ .name = ASPEED_JTAG_NAME, -+ .of_match_table = aspeed_jtag_of_match, -+ }, -+}; -+module_platform_driver(aspeed_jtag_driver); -+ -+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 2026-04-08 18:03:44.029783536 +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; -+}; ++ int rc; ++ netdev_tx_t ret; + -+static DEFINE_IDA(jtag_ida); ++ pr_debug("%s: skb len %u\n", __func__, skb->len); + -+void *jtag_priv(struct jtag *jtag) -+{ -+ return jtag->priv; ++ 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; +} -+EXPORT_SYMBOL_GPL(jtag_priv); + -+static long jtag_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++static void mctp_pcie_vdm_uninit(struct net_device *ndev) +{ -+ 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); ++ struct mctp_pcie_vdm_dev *vdm_dev; + -+ if (put_user(value, (__u32 __user *)arg)) -+ err = -EFAULT; -+ break; ++ vdm_dev = netdev_priv(ndev); ++ pr_info("%s: uninitializing vdm_dev %s\n", __func__, ++ ndev->name); ++ vdm_dev->callback_ops->uninit(vdm_dev->dev); ++} + -+ case JTAG_SIOCFREQ: -+ if (!jtag->ops->freq_set) -+ return -EOPNOTSUPP; ++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)); + -+ if (get_user(value, (__u32 __user *)arg)) -+ return -EFAULT; -+ if (value == 0) -+ return -EINVAL; ++ 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); ++ } + -+ err = jtag->ops->freq_set(jtag, value); -+ dev_dbg(jtag->miscdev.parent, "JTAG_SIOCFREQ: freq set = %d", -+ value); -+ break; ++ if (saddr) { ++ pr_debug("%s src addr %d\n", __func__, *(u16 *)saddr); ++ hdr->pci_req_id = *(u16 *)saddr; ++ } + -+ case JTAG_SIOCSTATE: -+ if (copy_from_user(&tapstate, (const void __user *)arg, -+ sizeof(struct jtag_tap_state))) -+ return -EFAULT; ++ return 0; ++} + -+ if (tapstate.from > JTAG_STATE_CURRENT) -+ return -EINVAL; ++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, ++}; + -+ if (tapstate.endstate > JTAG_STATE_CURRENT) -+ return -EINVAL; ++static const struct header_ops mctp_pcie_vdm_net_hdr_ops = { ++ .create = mctp_pcie_vdm_hdr_create, ++}; + -+ if (tapstate.reset > JTAG_FORCE_RESET) -+ return -EINVAL; ++static void mctp_pcie_vdm_net_setup(struct net_device *ndev) ++{ ++ ndev->type = ARPHRD_MCTP; + -+ 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); ++ 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); + -+ err = jtag->ops->status_set(jtag, &tapstate); -+ break; ++ ndev->netdev_ops = &mctp_pcie_vdm_net_ops; ++ ndev->header_ops = &mctp_pcie_vdm_net_hdr_ops; ++} + -+ case JTAG_IOCXFER: -+ { -+ u8 ubit_mask = GENMASK(7, 0); -+ u8 remaining_bits = 0x0; -+ union pad_config padding; ++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 (copy_from_user(&xfer, (const void __user *)arg, -+ sizeof(struct jtag_xfer))) -+ return -EFAULT; ++ if (!ndev) { ++ pr_err("%s: failed to allocate net device\n", __func__); ++ return -ENOMEM; ++ } ++ dev_net_set(ndev, current->nsproxy->net_ns); + -+ if (xfer.length >= JTAG_MAX_XFER_DATA_LEN) -+ return -EINVAL; ++ *dev = ndev; ++ int rc; + -+ if (xfer.type > JTAG_SDR_XFER) -+ return -EINVAL; ++ 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; ++} + -+ if (xfer.direction > JTAG_READ_WRITE_XFER) -+ return -EINVAL; ++void mctp_pcie_vdm_receive_packet(struct net_device *ndev) ++{ ++ struct mctp_pcie_vdm_dev *vdm_dev; ++ u8 *packet; + -+ if (xfer.from > JTAG_STATE_CURRENT) -+ return -EINVAL; ++ vdm_dev = netdev_priv(ndev); ++ packet = vdm_dev->callback_ops->recv_packet(vdm_dev->dev); + -+ if (xfer.endstate > JTAG_STATE_CURRENT) -+ return -EINVAL; ++ 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; + -+ data_size = DIV_ROUND_UP(xfer.length, BITS_PER_BYTE); -+ xfer_data = memdup_user(u64_to_user_ptr(xfer.tdio), data_size); ++ 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); + -+ /* 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 (!skb) { ++ stats->rx_errors++; ++ pr_err("%s: failed to alloc skb\n", __func__); ++ continue; + } + -+ 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); ++ 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); + -+ print_hex_dump_debug("I:", DUMP_PREFIX_NONE, 16, 1, xfer_data, -+ data_size, false); ++ 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; + -+ err = jtag->ops->xfer(jtag, &xfer, xfer_data); -+ if (err) { -+ kfree(xfer_data); -+ return err; ++ net_status = netif_rx(skb); ++ if (net_status == NET_RX_SUCCESS) { ++ stats->rx_packets++; ++ stats->rx_bytes += len; ++ } else { ++ stats->rx_dropped++; + } + -+ 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; ++ vdm_dev->callback_ops->free_packet(packet); ++ packet = vdm_dev->callback_ops->recv_packet(vdm_dev->dev); + } ++} + -+ 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; ++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; + -+ default: -+ return -EINVAL; ++ rc = mctp_pcie_vdm_add_net_dev(&ndev); ++ if (rc) { ++ pr_err("%s: failed to add net device\n", __func__); ++ return ERR_PTR(rc); + } -+ return err; -+} + -+static int jtag_open(struct inode *inode, struct file *file) -+{ -+ struct jtag *jtag = container_of(file->private_data, -+ struct jtag, -+ miscdev); ++ vdm_dev = netdev_priv(ndev); ++ vdm_dev->dev = dev; ++ vdm_dev->callback_ops = ops; + -+ file->private_data = jtag; -+ if (jtag->ops->enable(jtag)) -+ return -EBUSY; -+ return nonseekable_open(inode, file); ++ return ndev; +} ++EXPORT_SYMBOL_GPL(mctp_pcie_vdm_add_dev); + -+static int jtag_release(struct inode *inode, struct file *file) ++void mctp_pcie_vdm_remove_dev(struct net_device *vdm_dev) +{ -+ struct jtag *jtag = file->private_data; ++ pr_debug("%s: removing vdm_dev %s\n", __func__, vdm_dev->name); + -+ if (jtag->ops->disable(jtag)) -+ return -EBUSY; -+ return 0; ++ 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 @@ + | FIELD_PREP(ASPEED_MDIO_DATA_MIIRDATA, data); + + iowrite32(ctrl, 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. + -+static const struct file_operations jtag_fops = { -+ .owner = THIS_MODULE, -+ .open = jtag_open, -+ .llseek = noop_llseek, -+ .unlocked_ioctl = jtag_ioctl, -+ .release = jtag_release, -+}; + 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 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * PCIe host controller driver for ASPEED PCIe Bridge ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+struct jtag *jtag_alloc(struct device *host, size_t priv_size, -+ const struct jtag_ops *ops) -+{ -+ struct jtag *jtag; ++#include "../pci.h" + -+ if (!host) -+ return NULL; ++#define MAX_MSI_HOST_IRQS 64 + -+ if (!ops) -+ return NULL; ++/* AST2600 AHBC Registers */ ++#define AHBC_KEY 0x00 ++#define AHBC_UNLOCK 0xAEED1A03 ++#define AHBC_ADDR_MAPPING 0x8C ++#define PCIE_RC_MEMORY_EN BIT(5) + -+ if (!ops->status_set || !ops->status_get || !ops->xfer) -+ return NULL; ++/* AST2600 PCIe Host Controller Registers */ ++#define PEHR_MISC_10 0x10 ++#define DATALINK_REPORT_CAPABLE BIT(4) ++#define PEHR_MISC_14 0x14 ++#define HOTPLUG_CAPABLE_ENABLE BIT(6) ++#define HOTPLUG_SURPRISE_ENABLE BIT(5) ++#define ATTENTION_BUTTON_ENABLE BIT(0) ++#define PEHR_GLOBAL 0x30 ++#define RC_SYNC_RESET_DISABLE BIT(20) ++#define PCIE_RC_SLOT_ENABLE BIT(1) ++#define ROOT_COMPLEX_ID(x) ((x) << 4) ++#define PEHR_LOCK 0x7C ++#define PCIE_UNLOCK 0xa8 ++#define PEHR_LINK 0xC0 ++#define PCIE_LINK_STS BIT(5) + -+ jtag = kzalloc(sizeof(*jtag), GFP_KERNEL); -+ if (!jtag) -+ return NULL; -+ jtag->priv = kzalloc(priv_size, GFP_KERNEL); -+ if (!jtag->priv) -+ return NULL; ++/* AST2600 H2X Controller Registers */ ++/* Common Registers*/ ++#define H2X_INT_STS 0x08 ++#define PCIE_TX_IDLE_CLEAR BIT(0) ++#define H2X_TX_DESC0 0x10 ++#define H2X_TX_DESC1 0x14 ++#define H2X_TX_DESC2 0x18 ++#define H2X_TX_DESC3 0x1C ++#define H2X_TX_DESC_DATA 0x20 ++#define H2X_STS 0x24 ++#define PCIE_TX_IDLE BIT(31) ++#define PCIE_STATUS_OF_TX GENMASK(25, 24) ++#define PCIE_RC_L_TX_COMPLETE BIT(24) ++#define PCIE_RC_H_TX_COMPLETE BIT(25) ++#define PCIE_TRIGGER_TX BIT(0) ++#define H2X_AHB_ADDR_CONFIG0 0x60 ++#define H2X_AHB_ADDR_CONFIG1 0x64 ++#define H2X_AHB_ADDR_CONFIG2 0x68 ++/* Device Registers */ ++#define H2X_DEV_CTRL 0x00 ++#define PCIE_RX_DMA_EN BIT(9) ++#define PCIE_RX_LINEAR BIT(8) ++#define PCIE_RX_MSI_SEL BIT(7) ++#define PCIE_RX_MSI_EN BIT(6) ++#define PCIE_UNLOCK_RX_BUFF BIT(4) ++#define PCIE_Wait_RX_TLP_CLR BIT(2) ++#define PCIE_RC_RX_ENABLE BIT(1) ++#define PCIE_RC_ENABLE BIT(0) ++#define H2X_DEV_STS 0x08 ++#define PCIE_RC_RX_DONE_ISR BIT(4) ++#define H2X_DEV_RX_DESC_DATA 0x0C ++#define H2X_DEV_RX_DESC1 0x14 ++#define H2X_DEV_TX_TAG 0x3C + -+ jtag->ops = ops; -+ jtag->miscdev.parent = host; ++/* AST2700 H2X */ ++#define H2X_CTRL 0x00 ++#define H2X_BRIDGE_EN BIT(0) ++#define H2X_BRIDGE_DIRECT_EN BIT(1) ++#define H2X_CFGE_INT_STS 0x08 ++#define CFGE_TX_IDLE BIT(0) ++#define CFGE_RX_BUSY BIT(1) ++#define H2X_CFGI_TLP 0x20 ++#define H2X_CFGI_WR_DATA 0x24 ++#define H2X_CFGI_CTRL 0x28 ++#define CFGI_TLP_FIRE BIT(0) ++#define H2X_CFGI_RET_DATA 0x2C ++#define H2X_CFGE_TLP_1ST 0x30 ++#define H2X_CFGE_TLP_NEXT 0x34 ++#define H2X_CFGE_CTRL 0x38 ++#define CFGE_TLP_FIRE BIT(0) ++#define H2X_CFGE_RET_DATA 0x3C ++#define H2X_REMAP_PREF_ADDR 0x70 ++#define H2X_REMAP_DIRECT_ADDR 0x78 + -+ return jtag; -+} -+EXPORT_SYMBOL_GPL(jtag_alloc); ++/* AST2700 PEHR */ ++#define PEHR_VID_DID 0x00 ++#define PEHR_MISC_44 0x44 ++#define ENABLE_SLOT_CAP BIT(12) ++#define PEHR_MISC_38 0x38 ++#define DATALINK_REPORT_CAP BIT(20) ++#define PEHR_MISC_3C 0x3C ++#define PEHR_MISC_58 0x58 ++#define LOCAL_SCALE_SUP BIT(0) ++#define PEHR_MISC_5C 0x5C ++#define PEHR_MISC_60 0x60 ++#define PORT_TPYE GENMASK(7, 4) ++#define PORT_TYPE_ROOT BIT(2) ++#define PEHR_MISC_70 0x70 ++#define PEHR_MISC_78 0x78 ++#define PEHR_MISC_1B8 0x1B8 ++#define SW_ATT_BTN BIT(0) ++#define PEHR_MISC_344 0x344 ++#define LINK_STATUS_GEN2 BIT(18) ++#define PEHR_MISC_358 0x358 ++#define LINK_STATUS_GEN4 BIT(8) + -+void jtag_free(struct jtag *jtag) -+{ -+ kfree(jtag); -+} -+EXPORT_SYMBOL_GPL(jtag_free); ++/* AST2700 SCU */ ++#define SCU_60 0x60 ++#define RC_E2M_PATH_EN BIT(0) ++#define RC_H2XS_PATH_EN BIT(16) ++#define RC_H2XD_PATH_EN BIT(17) ++#define RC_H2XX_PATH_EN BIT(18) ++#define RC_UPSTREAM_MEM_EN BIT(19) ++#define SCU_64 0x64 ++#define SCU_70 0x70 ++#define SCU_78 0x78 + -+static int jtag_register(struct jtag *jtag) -+{ -+ struct device *dev = jtag->miscdev.parent; -+ int err; -+ int id; ++/* TLP configuration type 0 and type 1 */ ++#define CRG_READ_FMTTYPE(type) (0x04000000 | (type << 24)) ++#define CRG_WRITE_FMTTYPE(type) (0x44000000 | (type << 24)) ++#define CRG_PAYLOAD_SIZE 0x01 /* 1 DWORD */ ++#define TLP_COMP_STATUS(s) (((s) >> 13) & 7) + -+ if (!dev) -+ return -ENODEV; ++struct aspeed_pcie_rc_platform { ++ int (*setup)(struct platform_device *pdev); ++ /* Interrupt Register Offset */ ++ int reg_intx_en; ++ int reg_intx_sts; ++ int reg_msi_en; ++ int reg_msi_sts; ++ int msi_address; ++}; + -+ id = ida_simple_get(&jtag_ida, 0, 0, GFP_KERNEL); -+ if (id < 0) -+ return id; ++struct aspeed_pcie { ++ struct pci_host_bridge *host; ++ struct device *dev; ++ void __iomem *reg; ++ struct regmap *ahbc; ++ struct regmap *cfg; ++ struct regmap *pciephy; ++ struct clk *clock; ++ const struct aspeed_pcie_rc_platform *platform; + -+ jtag->id = id; ++ int domain; ++ u8 tx_tag; ++ int host_bus_num; + -+ 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; -+ } ++ struct reset_control *h2xrst; ++ struct reset_control *perst; + -+ err = misc_register(&jtag->miscdev); -+ if (err) { -+ dev_err(jtag->miscdev.parent, "Unable to register device\n"); -+ goto err_jtag_name; -+ } -+ return 0; ++ struct irq_domain *irq_domain; ++ struct irq_domain *dev_domain; ++ struct irq_domain *msi_domain; ++ /* Protects MSI IRQ allocation and release */ ++ struct mutex lock; + -+err_jtag_name: -+ kfree(jtag->miscdev.name); -+err_jtag_alloc: -+ ida_simple_remove(&jtag_ida, id); -+ return err; -+} ++ int hotplug_event; ++ struct gpio_desc *perst_ep_in; ++ struct gpio_desc *perst_rc_out; ++ struct gpio_desc *perst_owner; ++ struct delayed_work rst_dwork; ++ DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_HOST_IRQS); ++}; + -+static void jtag_unregister(struct jtag *jtag) ++static void aspeed_pcie_intx_ack_irq(struct irq_data *d) +{ -+ misc_deregister(&jtag->miscdev); -+ kfree(jtag->miscdev.name); -+ ida_simple_remove(&jtag_ida, jtag->id); -+} ++ struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(d); ++ int intx_en = pcie->platform->reg_intx_en; + -+static void devm_jtag_unregister(struct device *dev, void *res) -+{ -+ jtag_unregister(*(struct jtag **)res); ++ writel(readl(pcie->reg + intx_en) | BIT(d->hwirq), pcie->reg + intx_en); +} + -+int devm_jtag_register(struct device *dev, struct jtag *jtag) ++static void aspeed_pcie_intx_mask_irq(struct irq_data *d) +{ -+ struct jtag **ptr; -+ int ret; -+ -+ ptr = devres_alloc(devm_jtag_unregister, sizeof(struct jtag *), -+ GFP_KERNEL); -+ if (!ptr) -+ return -ENOMEM; ++ struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(d); ++ int intx_en = pcie->platform->reg_intx_en; + -+ ret = jtag_register(jtag); -+ if (!ret) { -+ *ptr = jtag; -+ devres_add(dev, ptr); -+ } else { -+ devres_free(ptr); -+ } -+ return ret; ++ writel(readl(pcie->reg + intx_en) & ~BIT(d->hwirq), pcie->reg + intx_en); +} -+EXPORT_SYMBOL_GPL(devm_jtag_register); + -+static void __exit jtag_exit(void) ++static void aspeed_pcie_intx_unmask_irq(struct irq_data *d) +{ -+ ida_destroy(&jtag_ida); ++ 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); +} + -+module_exit(jtag_exit); ++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, ++}; + -+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 2026-04-08 18:03:34.959949087 +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. ++static int aspeed_pcie_intx_map(struct irq_domain *domain, unsigned int irq, ++ irq_hw_number_t hwirq) ++{ ++ irq_set_chip_and_handler(irq, &aspeed_intx_irq_chip, handle_level_irq); ++ irq_set_chip_data(irq, domain->host_data); ++ irq_set_status_flags(irq, IRQ_LEVEL); + - 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 2026-04-08 18:03:39.858859736 +0000 -@@ -64,3 +64,5 @@ - obj-$(CONFIG_QCOM_CPUCP_MBOX) += qcom-cpucp-mbox.o - - obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o ++ return 0; ++} + -+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 2026-04-08 18:03:48.220706964 +0000 -@@ -0,0 +1,235 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Copyright Aspeed Technology Inc. (C) 2025. All rights reserved -+ */ ++static const struct irq_domain_ops aspeed_intx_domain_ops = { ++ .map = aspeed_pcie_intx_map, ++}; + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++static irqreturn_t aspeed_pcie_intr_handler(int irq, void *dev_id) ++{ ++ struct aspeed_pcie *pcie = dev_id; ++ const struct aspeed_pcie_rc_platform *platform = pcie->platform; ++ unsigned long status; ++ unsigned long intx; ++ u32 bit; ++ int i; + -+/* Each bit in the register represents an IPC ID */ -+#define IPCR_TX_TRIG 0x00 -+#define IPCR_ENABLE 0x04 -+#define IPCR_STATUS 0x08 -+#define RX_IRQ(n) BIT(n) -+#define RX_IRQ_MASK 0xf -+#define IPCR_DATA 0x10 ++ intx = readl(pcie->reg + platform->reg_intx_sts) & 0xf; ++ if (intx) { ++ for_each_set_bit(bit, &intx, PCI_NUM_INTX) ++ generic_handle_domain_irq(pcie->irq_domain, bit); ++ } + -+struct ast2700_mbox_data { -+ u8 num_chans; -+ u8 msg_size; -+}; ++ if (IS_ENABLED(CONFIG_PCI_MSI)) { ++ for (i = 0; i < 2; i++) { ++ status = readl(pcie->reg + platform->reg_msi_sts + (i * 4)); ++ writel(status, pcie->reg + platform->reg_msi_sts + (i * 4)); ++ /* Workaround: AST2700 MSI needs to cleat status twice */ ++ if (of_device_is_compatible(pcie->dev->of_node, "aspeed,ast2700-pcie")) ++ writel(status, pcie->reg + platform->reg_msi_sts + (i * 4)); ++ if (!status) ++ continue; + -+struct ast2700_mbox { -+ struct mbox_controller mbox; -+ u8 msg_size; -+ void __iomem *tx_regs; -+ void __iomem *rx_regs; -+ spinlock_t lock; /* control register lock */ -+}; ++ for_each_set_bit(bit, &status, 32) { ++ if (i) ++ bit += 32; ++ generic_handle_domain_irq(pcie->dev_domain, bit); ++ } ++ } ++ } + -+static inline int ch_num(struct mbox_chan *chan) -+{ -+ return chan - chan->mbox->chans; ++ return IRQ_HANDLED; +} + -+static inline bool ast2700_mbox_tx_done(struct ast2700_mbox *mb, int idx) ++static int aspeed_ast2600_rd_conf(struct pci_bus *bus, unsigned int devfn, ++ int where, int size, u32 *val) +{ -+ return !(readl(mb->tx_regs + IPCR_STATUS) & BIT(idx)); -+} ++ struct aspeed_pcie *pcie = bus->sysdata; ++ u32 bdf_offset; ++ int rx_done_fail = 0, slot = PCI_SLOT(devfn); ++ u32 cfg_val, isr, type = 0; ++ u32 link_sts = 0; ++ int ret; + -+static irqreturn_t ast2700_mbox_irq(int irq, void *p) -+{ -+ struct ast2700_mbox *mb = p; -+ void __iomem *data_reg; -+ int num_words = mb->msg_size / sizeof(u32); -+ u32 *word_data; -+ u32 status; -+ int n, i; ++ /* Driver may set unlock RX buffere before triggering next TX config */ ++ writel(PCIE_UNLOCK_RX_BUFF | readl(pcie->reg + H2X_DEV_CTRL), ++ pcie->reg + H2X_DEV_CTRL); + -+ /* Only examine channels that are currently enabled. */ -+ status = readl(mb->rx_regs + IPCR_ENABLE) & -+ readl(mb->rx_regs + IPCR_STATUS); ++ if (bus->number == pcie->host_bus_num && slot != 0 && slot != 8) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ type = (bus->number > pcie->host_bus_num); + -+ if (!(status & RX_IRQ_MASK)) -+ return IRQ_NONE; ++ if (type) { ++ regmap_read(pcie->pciephy, PEHR_LINK, &link_sts); ++ if (!(link_sts & PCIE_LINK_STS)) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ } + -+ for (n = 0; n < mb->mbox.num_chans; ++n) { -+ struct mbox_chan *chan = &mb->mbox.chans[n]; ++ bdf_offset = ((bus->number) << 24) | (PCI_SLOT(devfn) << 19) | ++ (PCI_FUNC(devfn) << 16) | (where & ~3); + -+ if (!(status & RX_IRQ(n))) -+ continue; ++ pcie->tx_tag %= 0x7; + -+ data_reg = mb->rx_regs + IPCR_DATA + mb->msg_size * n; -+ word_data = chan->con_priv; -+ /* Read the message data */ -+ for (i = 0; i < num_words; i++) -+ word_data[i] = readl(data_reg + i * sizeof(u32)); ++ regmap_write(pcie->cfg, H2X_TX_DESC0, 0x04000001 | (type << 24)); ++ regmap_write(pcie->cfg, H2X_TX_DESC1, 0x0000200f | (pcie->tx_tag << 8)); ++ regmap_write(pcie->cfg, H2X_TX_DESC2, bdf_offset); ++ regmap_write(pcie->cfg, H2X_TX_DESC3, 0x00000000); + -+ mbox_chan_received_data(chan, chan->con_priv); ++ regmap_write_bits(pcie->cfg, H2X_STS, PCIE_TRIGGER_TX, PCIE_TRIGGER_TX); + -+ /* The IRQ can be cleared only once the FIFO is empty. */ -+ writel(RX_IRQ(n), mb->rx_regs + IPCR_STATUS); ++ ret = regmap_read_poll_timeout(pcie->cfg, H2X_STS, cfg_val, ++ (cfg_val & PCIE_TX_IDLE), 0, 50); ++ if (ret) { ++ dev_err(pcie->dev, ++ "[%X:%02X:%02X.%02X]CR tx timeout sts: 0x%08x\n", ++ pcie->domain, bus->number, PCI_SLOT(devfn), ++ PCI_FUNC(devfn), cfg_val); ++ goto out; + } + -+ return IRQ_HANDLED; -+} ++ regmap_write_bits(pcie->cfg, H2X_INT_STS, PCIE_TX_IDLE_CLEAR, ++ PCIE_TX_IDLE_CLEAR); + -+static int ast2700_mbox_send_data(struct mbox_chan *chan, void *data) -+{ -+ struct ast2700_mbox *mb = dev_get_drvdata(chan->mbox->dev); -+ int idx = ch_num(chan); -+ void __iomem *data_reg = mb->tx_regs + IPCR_DATA + mb->msg_size * idx; -+ u32 *word_data = data; -+ int num_words = mb->msg_size / sizeof(u32); -+ int i; ++ regmap_read(pcie->cfg, H2X_STS, &cfg_val); ++ switch (cfg_val & PCIE_STATUS_OF_TX) { ++ case PCIE_RC_L_TX_COMPLETE: ++ case PCIE_RC_H_TX_COMPLETE: ++ ret = readl_poll_timeout(pcie->reg + H2X_DEV_STS, isr, ++ (isr & PCIE_RC_RX_DONE_ISR), 0, 50); ++ if (ret) { ++ dev_err(pcie->dev, ++ "[%X:%02X:%02X.%02X]CR rx timeoutsts: 0x%08x\n", ++ pcie->domain, bus->number, PCI_SLOT(devfn), ++ PCI_FUNC(devfn), isr); ++ rx_done_fail = 1; ++ *val = ~0; ++ } ++ if (!rx_done_fail) { ++ if (readl(pcie->reg + H2X_DEV_RX_DESC1) & BIT(13)) ++ *val = ~0; ++ else ++ *val = readl(pcie->reg + H2X_DEV_RX_DESC_DATA); ++ } + -+ if (!(readl(mb->tx_regs + IPCR_ENABLE) & BIT(idx))) { -+ dev_warn(mb->mbox.dev, "%s: Ch-%d not enabled yet\n", __func__, idx); -+ return -ENODEV; ++ writel(PCIE_UNLOCK_RX_BUFF | readl(pcie->reg + H2X_DEV_CTRL), ++ pcie->reg + H2X_DEV_CTRL); ++ break; ++ case PCIE_STATUS_OF_TX: ++ *val = ~0; ++ break; ++ default: ++ regmap_read(pcie->cfg, H2X_DEV_RX_DESC_DATA, &cfg_val); ++ *val = cfg_val; ++ break; + } + -+ if (!(ast2700_mbox_tx_done(mb, idx))) { -+ dev_warn(mb->mbox.dev, "%s: Ch-%d last data has not finished\n", __func__, idx); -+ return -EBUSY; ++ switch (size) { ++ case 1: ++ *val = (*val >> ((where & 3) * 8)) & 0xff; ++ break; ++ case 2: ++ *val = (*val >> ((where & 2) * 8)) & 0xffff; ++ break; + } + -+ /* Write the message data */ -+ for (i = 0 ; i < num_words; i++) -+ writel(word_data[i], data_reg + i * sizeof(u32)); -+ -+ writel(BIT(idx), mb->tx_regs + IPCR_TX_TRIG); -+ dev_dbg(mb->mbox.dev, "%s: Ch-%d sent\n", __func__, idx); ++ if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) { ++ if (where == (0x80 + PCI_EXP_SLTSTA) && ++ bus->number == pcie->host_bus_num && ++ PCI_SLOT(devfn) == 0x8 && ++ PCI_FUNC(devfn) == 0x0 && ++ pcie->hotplug_event) ++ *val |= PCI_EXP_SLTSTA_ABP; ++ } + -+ return 0; ++ ret = PCIBIOS_SUCCESSFUL; ++out: ++ writel(readl(pcie->reg + H2X_DEV_STS), pcie->reg + H2X_DEV_STS); ++ pcie->tx_tag++; ++ return ret; +} + -+static int ast2700_mbox_startup(struct mbox_chan *chan) ++static int aspeed_ast2600_wr_conf(struct pci_bus *bus, unsigned int devfn, ++ int where, int size, u32 val) +{ -+ struct ast2700_mbox *mb = dev_get_drvdata(chan->mbox->dev); -+ int idx = ch_num(chan); -+ void __iomem *reg = mb->rx_regs + IPCR_ENABLE; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&mb->lock, flags); -+ writel(readl(reg) | BIT(idx), reg); -+ spin_unlock_irqrestore(&mb->lock, flags); ++ u32 type = 0; ++ u32 shift = 8 * (where & 3); ++ u32 bdf_offset; ++ u8 byte_en = 0; ++ struct aspeed_pcie *pcie = bus->sysdata; ++ u32 isr, cfg_val; ++ int ret; + -+ return 0; -+} ++ if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) { ++ if (where == (0x80 + PCI_EXP_SLTSTA) && ++ bus->number == pcie->host_bus_num && ++ PCI_SLOT(devfn) == 0x8 && ++ PCI_FUNC(devfn) == 0x0 && ++ pcie->hotplug_event && ++ (val & PCI_EXP_SLTSTA_ABP)) { ++ pcie->hotplug_event = 0; ++ return PCIBIOS_SUCCESSFUL; ++ } ++ } + -+static void ast2700_mbox_shutdown(struct mbox_chan *chan) -+{ -+ struct ast2700_mbox *mb = dev_get_drvdata(chan->mbox->dev); -+ int idx = ch_num(chan); -+ void __iomem *reg = mb->rx_regs + IPCR_ENABLE; -+ unsigned long flags; ++ /* Driver may set unlock RX buffere before triggering next TX config */ ++ writel(PCIE_UNLOCK_RX_BUFF | readl(pcie->reg + H2X_DEV_CTRL), ++ pcie->reg + H2X_DEV_CTRL); + -+ spin_lock_irqsave(&mb->lock, flags); -+ writel(readl(reg) & ~BIT(idx), reg); -+ spin_unlock_irqrestore(&mb->lock, flags); ++ switch (size) { ++ case 1: ++ byte_en = 1 << (where % 4); ++ val = (val & 0xff) << shift; ++ break; ++ case 2: ++ byte_en = 0x3 << (2 * ((where >> 1) % 2)); ++ val = (val & 0xffff) << shift; ++ break; ++ default: ++ byte_en = 0xf; ++ break; ++ } ++ ++ type = (bus->number > pcie->host_bus_num); ++ ++ bdf_offset = (bus->number << 24) | (PCI_SLOT(devfn) << 19) | ++ (PCI_FUNC(devfn) << 16) | (where & ~3); ++ pcie->tx_tag %= 0x7; ++ ++ regmap_write(pcie->cfg, H2X_TX_DESC0, 0x44000001 | (type << 24)); ++ regmap_write(pcie->cfg, H2X_TX_DESC1, ++ 0x00002000 | (pcie->tx_tag << 8) | byte_en); ++ regmap_write(pcie->cfg, H2X_TX_DESC2, bdf_offset); ++ regmap_write(pcie->cfg, H2X_TX_DESC3, 0x00000000); ++ regmap_write(pcie->cfg, H2X_TX_DESC_DATA, val); ++ ++ regmap_write_bits(pcie->cfg, H2X_STS, PCIE_TRIGGER_TX, PCIE_TRIGGER_TX); ++ ++ ret = regmap_read_poll_timeout(pcie->cfg, H2X_STS, cfg_val, ++ (cfg_val & PCIE_TX_IDLE), 0, 50); ++ if (ret) { ++ dev_err(pcie->dev, ++ "[%X:%02X:%02X.%02X]CT tx timeout sts: 0x%08x\n", ++ pcie->domain, bus->number, PCI_SLOT(devfn), ++ PCI_FUNC(devfn), cfg_val); ++ ret = PCIBIOS_SET_FAILED; ++ goto out; ++ } ++ ++ regmap_write_bits(pcie->cfg, H2X_INT_STS, PCIE_TX_IDLE_CLEAR, ++ PCIE_TX_IDLE_CLEAR); ++ ++ regmap_read(pcie->cfg, H2X_STS, &cfg_val); ++ switch (cfg_val & PCIE_STATUS_OF_TX) { ++ case PCIE_RC_L_TX_COMPLETE: ++ case PCIE_RC_H_TX_COMPLETE: ++ ret = readl_poll_timeout(pcie->reg + H2X_DEV_STS, isr, ++ (isr & PCIE_RC_RX_DONE_ISR), 0, 50); ++ if (ret) { ++ dev_err(pcie->dev, ++ "[%X:%02X:%02X.%02X]CT rx timeout sts: 0x%08x\n", ++ pcie->domain, bus->number, PCI_SLOT(devfn), ++ PCI_FUNC(devfn), isr); ++ ret = PCIBIOS_SET_FAILED; ++ goto out; ++ } ++ break; ++ } ++ ret = PCIBIOS_SUCCESSFUL; ++out: ++ writel(readl(pcie->reg + H2X_DEV_STS), pcie->reg + H2X_DEV_STS); ++ pcie->tx_tag++; ++ return ret; +} + -+static bool ast2700_mbox_last_tx_done(struct mbox_chan *chan) ++static bool aspeed_ast2700_get_link(struct aspeed_pcie *pcie) +{ -+ struct ast2700_mbox *mb = dev_get_drvdata(chan->mbox->dev); -+ int idx = ch_num(chan); ++ u32 reg; ++ bool link; + -+ return ast2700_mbox_tx_done(mb, idx); -+} ++ if (pcie->domain == 2) { ++ regmap_read(pcie->pciephy, PEHR_MISC_344, ®); ++ link = !!(reg & LINK_STATUS_GEN2); ++ } else { ++ regmap_read(pcie->pciephy, PEHR_MISC_358, ®); ++ link = !!(reg & LINK_STATUS_GEN4); ++ } + -+static const struct mbox_chan_ops ast2700_mbox_chan_ops = { -+ .send_data = ast2700_mbox_send_data, -+ .startup = ast2700_mbox_startup, -+ .shutdown = ast2700_mbox_shutdown, -+ .last_tx_done = ast2700_mbox_last_tx_done, -+}; ++ return link; ++} + -+static int ast2700_mbox_probe(struct platform_device *pdev) ++static int aspeed_ast2700_rd_conf(struct pci_bus *bus, unsigned int devfn, ++ int where, int size, u32 *val) +{ -+ struct ast2700_mbox *mb; -+ const struct ast2700_mbox_data *dev_data; -+ struct device *dev = &pdev->dev; -+ int irq, ret; ++ struct aspeed_pcie *pcie = bus->sysdata; ++ u32 bdf_offset, status; ++ u8 type; ++ int ret; + -+ if (!pdev->dev.of_node) -+ return -ENODEV; ++ if ((bus->number == pcie->host_bus_num && devfn != 0)) ++ return PCIBIOS_DEVICE_NOT_FOUND; + -+ dev_data = device_get_match_data(&pdev->dev); ++ if (bus->number == pcie->host_bus_num) { ++ /* Internal access to bridge */ ++ writel(0xF << 16 | (where & ~3), pcie->reg + H2X_CFGI_TLP); ++ writel(CFGI_TLP_FIRE, pcie->reg + H2X_CFGI_CTRL); ++ *val = readl(pcie->reg + H2X_CFGI_RET_DATA); ++ } else { ++ if (!aspeed_ast2700_get_link(pcie)) ++ return PCIBIOS_DEVICE_NOT_FOUND; + -+ mb = devm_kzalloc(dev, sizeof(*mb), GFP_KERNEL); -+ if (!mb) -+ return -ENOMEM; ++ bdf_offset = ((bus->number) << 24) | (PCI_SLOT(devfn) << 19) | ++ (PCI_FUNC(devfn) << 16) | (where & ~3); + -+ mb->mbox.chans = devm_kcalloc(&pdev->dev, dev_data->num_chans, -+ sizeof(*mb->mbox.chans), GFP_KERNEL); -+ if (!mb->mbox.chans) -+ return -ENOMEM; ++ pcie->tx_tag %= 0xF; + -+ /* con_priv of each channel is used to store the message received */ -+ for (int i = 0; i < dev_data->num_chans; i++) { -+ mb->mbox.chans[i].con_priv = devm_kcalloc(dev, dev_data->msg_size, -+ sizeof(u8), GFP_KERNEL); -+ if (!mb->mbox.chans[i].con_priv) -+ return -ENOMEM; ++ type = (bus->number == (pcie->host_bus_num + 1)) ? ++ PCI_HEADER_TYPE_NORMAL : ++ PCI_HEADER_TYPE_BRIDGE; ++ ++ writel(CRG_READ_FMTTYPE(type) | CRG_PAYLOAD_SIZE, pcie->reg + H2X_CFGE_TLP_1ST); ++ writel(0x40100F | (pcie->tx_tag << 8), pcie->reg + H2X_CFGE_TLP_NEXT); ++ writel(bdf_offset, pcie->reg + H2X_CFGE_TLP_NEXT); ++ writel(CFGE_TX_IDLE | CFGE_RX_BUSY, pcie->reg + H2X_CFGE_INT_STS); ++ writel(CFGE_TLP_FIRE, pcie->reg + H2X_CFGE_CTRL); ++ ++ ret = readl_poll_timeout(pcie->reg + H2X_CFGE_INT_STS, status, ++ (status & CFGE_TX_IDLE), 0, 50); ++ if (ret) { ++ dev_err(pcie->dev, ++ "[%X:%02X:%02X.%02X]CR tx timeout sts: 0x%08x\n", ++ pcie->domain, bus->number, PCI_SLOT(devfn), ++ PCI_FUNC(devfn), status); ++ goto out; ++ } ++ ++ ret = readl_poll_timeout(pcie->reg + H2X_CFGE_INT_STS, status, ++ (status & CFGE_RX_BUSY), 0, 50000); ++ if (ret) { ++ dev_err(pcie->dev, ++ "[%X:%02X:%02X.%02X]CR rx timeoutsts: 0x%08x\n", ++ pcie->domain, bus->number, PCI_SLOT(devfn), ++ PCI_FUNC(devfn), status); ++ goto out; ++ } ++ *val = readl(pcie->reg + H2X_CFGE_RET_DATA); + } + -+ platform_set_drvdata(pdev, mb); ++ switch (size) { ++ case 1: ++ *val = (*val >> ((where & 3) * 8)) & 0xff; ++ break; ++ case 2: ++ *val = (*val >> ((where & 2) * 8)) & 0xffff; ++ break; ++ } + -+ mb->tx_regs = devm_platform_ioremap_resource_byname(pdev, "tx"); -+ if (IS_ERR(mb->tx_regs)) -+ return PTR_ERR(mb->tx_regs); ++ writel(status, pcie->reg + H2X_CFGE_INT_STS); ++ pcie->tx_tag++; ++ return PCIBIOS_SUCCESSFUL; ++out: ++ *val = ~0; ++ writel(status, pcie->reg + H2X_CFGE_INT_STS); ++ pcie->tx_tag++; ++ return PCIBIOS_SET_FAILED; ++} + -+ mb->rx_regs = devm_platform_ioremap_resource_byname(pdev, "rx"); -+ if (IS_ERR(mb->rx_regs)) -+ return PTR_ERR(mb->rx_regs); ++static int aspeed_ast2700_wr_conf(struct pci_bus *bus, unsigned int devfn, ++ int where, int size, u32 val) ++{ ++ struct aspeed_pcie *pcie = bus->sysdata; ++ u32 shift = 8 * (where & 3); ++ u8 byte_en; ++ u32 bdf_offset, status, type; ++ int ret; + -+ mb->msg_size = dev_data->msg_size; -+ mb->mbox.dev = dev; -+ mb->mbox.num_chans = dev_data->num_chans; -+ mb->mbox.ops = &ast2700_mbox_chan_ops; -+ mb->mbox.txdone_irq = false; -+ mb->mbox.txdone_poll = true; -+ mb->mbox.txpoll_period = 5; -+ spin_lock_init(&mb->lock); ++ if ((bus->number == pcie->host_bus_num && devfn != 0)) ++ return PCIBIOS_DEVICE_NOT_FOUND; + -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) -+ return irq; ++ switch (size) { ++ case 1: ++ byte_en = 1 << (where % 4); ++ val = (val & 0xff) << shift; ++ break; ++ case 2: ++ byte_en = 0x3 << (2 * ((where >> 1) % 2)); ++ val = (val & 0xffff) << shift; ++ break; ++ default: ++ byte_en = 0xf; ++ break; ++ } + -+ ret = devm_request_irq(dev, irq, ast2700_mbox_irq, 0, dev_name(dev), mb); -+ if (ret) -+ return ret; ++ if (bus->number == pcie->host_bus_num) { ++ /* Internal access to bridge */ ++ writel(0x100000 | byte_en << 16 | (where & ~3), pcie->reg + H2X_CFGI_TLP); ++ writel(val, pcie->reg + H2X_CFGI_WR_DATA); ++ writel(CFGI_TLP_FIRE, pcie->reg + H2X_CFGI_CTRL); ++ } else { ++ if (!aspeed_ast2700_get_link(pcie)) ++ return PCIBIOS_SET_FAILED; + -+ return devm_mbox_controller_register(dev, &mb->mbox); ++ bdf_offset = (bus->number << 24) | (PCI_SLOT(devfn) << 19) | ++ (PCI_FUNC(devfn) << 16) | (where & ~3); ++ pcie->tx_tag %= 0xF; ++ ++ type = (bus->number == (pcie->host_bus_num + 1)) ? ++ PCI_HEADER_TYPE_NORMAL : ++ PCI_HEADER_TYPE_BRIDGE; ++ ++ writel(CRG_WRITE_FMTTYPE(type) | CRG_PAYLOAD_SIZE, pcie->reg + H2X_CFGE_TLP_1ST); ++ writel(0x401000 | (pcie->tx_tag << 8) | byte_en, pcie->reg + H2X_CFGE_TLP_NEXT); ++ writel(bdf_offset, pcie->reg + H2X_CFGE_TLP_NEXT); ++ writel(val, pcie->reg + H2X_CFGE_TLP_NEXT); ++ writel(CFGE_TX_IDLE | CFGE_RX_BUSY, pcie->reg + H2X_CFGE_INT_STS); ++ writel(CFGE_TLP_FIRE, pcie->reg + H2X_CFGE_CTRL); ++ ++ ret = readl_poll_timeout(pcie->reg + H2X_CFGE_INT_STS, status, ++ (status & CFGE_TX_IDLE), 0, 50); ++ if (ret) { ++ dev_err(pcie->dev, ++ "[%X:%02X:%02X.%02X]CT tx timeout sts: 0x%08x\n", ++ pcie->domain, bus->number, PCI_SLOT(devfn), ++ PCI_FUNC(devfn), status); ++ ret = PCIBIOS_SET_FAILED; ++ goto out; ++ } ++ ++ ret = readl_poll_timeout(pcie->reg + H2X_CFGE_INT_STS, status, ++ (status & CFGE_RX_BUSY), 0, 50000); ++ if (ret) { ++ dev_err(pcie->dev, ++ "[%X:%02X:%02X.%02X]CT rx timeout sts: 0x%08x\n", ++ pcie->domain, bus->number, PCI_SLOT(devfn), ++ PCI_FUNC(devfn), status); ++ ret = PCIBIOS_SET_FAILED; ++ goto out; ++ } ++ ++ (void)readl(pcie->reg + H2X_CFGE_RET_DATA); ++ } ++ ret = PCIBIOS_SUCCESSFUL; ++out: ++ writel(status, pcie->reg + H2X_CFGE_INT_STS); ++ pcie->tx_tag++; ++ return ret; +} + -+static const struct ast2700_mbox_data ast2700_dev_data = { -+ .num_chans = 4, -+ .msg_size = 0x20, ++static struct pci_ops aspeed_ast2600_pcie_ops = { ++ .read = aspeed_ast2600_rd_conf, ++ .write = aspeed_ast2600_wr_conf, +}; + -+static const struct of_device_id ast2700_mbox_of_match[] = { -+ { .compatible = "aspeed,ast2700-mailbox", .data = &ast2700_dev_data }, -+ {} ++static struct pci_ops aspeed_ast2700_pcie_ops = { ++ .read = aspeed_ast2700_rd_conf, ++ .write = aspeed_ast2700_wr_conf, +}; -+MODULE_DEVICE_TABLE(of, ast2700_mbox_of_match); + -+static struct platform_driver ast2700_mbox_driver = { -+ .driver = { -+ .name = "ast2700-mailbox", -+ .of_match_table = ast2700_mbox_of_match, -+ }, -+ .probe = ast2700_mbox_probe, ++#ifdef CONFIG_PCI_MSI ++static void aspeed_msi_compose_msi_msg(struct irq_data *data, ++ struct msi_msg *msg) ++{ ++ struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(data); ++ ++ msg->address_hi = 0; ++ msg->address_lo = pcie->platform->msi_address; ++ msg->data = data->hwirq; ++} ++ ++static int aspeed_msi_set_affinity(struct irq_data *irq_data, ++ const struct cpumask *mask, bool force) ++{ ++ return -EINVAL; ++} ++ ++static struct irq_chip aspeed_msi_bottom_irq_chip = { ++ .name = "ASPEED MSI", ++ .irq_compose_msi_msg = aspeed_msi_compose_msi_msg, ++ .irq_set_affinity = aspeed_msi_set_affinity, +}; -+module_platform_driver(ast2700_mbox_driver); + -+MODULE_AUTHOR("Jammy Huang "); -+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 2026-04-08 18:03:48.318705174 +0000 -@@ -4,6 +4,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -25,6 +26,9 @@ - #include - #include - #include -+#include -+#include -+#include - #include - #include - #include -@@ -96,6 +100,7 @@ - #define VE_CTRL_INTERLACE BIT(14) - #define VE_CTRL_HSYNC_POL_CTRL BIT(15) - #define VE_CTRL_FRC GENMASK(23, 16) -+#define AST2600_VE_CTRL_EN_COMPARE_ONLY BIT(31) - - #define VE_TGS_0 0x00c - #define VE_TGS_1 0x010 -@@ -149,6 +154,8 @@ - #define AST2400_VE_COMP_SIZE_READ_BACK 0x078 - #define AST2600_VE_COMP_SIZE_READ_BACK 0x084 - -+#define VE_COMP_FRAME_COUNT_READ_BACK 0x07C ++static int aspeed_irq_msi_domain_alloc(struct irq_domain *domain, ++ unsigned int virq, unsigned int nr_irqs, ++ void *args) ++{ ++ struct aspeed_pcie *pcie = domain->host_data; ++ int bit; ++ int i; + - #define VE_SRC_LR_EDGE_DET 0x090 - #define VE_SRC_LR_EDGE_DET_LEFT GENMASK(11, 0) - #define VE_SRC_LR_EDGE_DET_NO_V BIT(12) -@@ -203,6 +210,51 @@ - #define VE_MEM_RESTRICT_START 0x310 - #define VE_MEM_RESTRICT_END 0x314 - -+/* SCU's registers */ -+#define SCU_MISC_CTRL 0xC0 -+#define SCU_DPLL_SOURCE BIT(20) ++ mutex_lock(&pcie->lock); + -+#define SCU_CLK_SEL 0x288 -+#define SCU_SOC_DISPLAY_SEL BIT(15) ++ bit = bitmap_find_free_region(pcie->msi_irq_in_use, MAX_MSI_HOST_IRQS, ++ get_count_order(nr_irqs)); + -+#define SCU_CLK_SEL2 0x304 -+#define SCU_VIDEO_OUTPUT_DELAY GENMASK(5, 0) ++ mutex_unlock(&pcie->lock); + -+#define SCU_CRT2CLK 0x350 -+#define SCU_CRT2CLK_N GENMASK(31, 16) -+#define SCU_CRT2CLK_R GENMASK(15, 0) ++ if (bit < 0) ++ return -ENOSPC; + -+#define SCU_MULTI_FUNC_12 0x440 -+#define SCU_MULTI_FUNC_CPU_SLI_DIR BIT(5) -+#define SCU_MULTI_FUNC_15 0x454 -+#define SCU_MULTI_FUNC_IO_SLI_DIR BIT(21) ++ for (i = 0; i < nr_irqs; i++) { ++ irq_domain_set_info(domain, virq + i, bit + i, ++ &aspeed_msi_bottom_irq_chip, ++ domain->host_data, handle_simple_irq, NULL, ++ NULL); ++ } + -+/* GFX's registers */ -+#define GFX_CTRL 0x60 -+#define GFX_CTRL_ENABLE BIT(0) -+#define GFX_CTRL_FMT GENMASK(9, 7) ++ return 0; ++} + -+#define GFX_H_DISPLAY 0x70 -+#define GFX_H_DISPLAY_DE GENMASK(28, 16) -+#define GFX_H_DISPLAY_TOTAL GENMASK(12, 0) ++static void aspeed_irq_msi_domain_free(struct irq_domain *domain, ++ unsigned int virq, unsigned int nr_irqs) ++{ ++ struct irq_data *data = irq_domain_get_irq_data(domain, virq); ++ struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(data); + -+#define GFX_V_DISPLAY 0x78 -+#define GFX_V_DISPLAY_DE GENMASK(27, 16) -+#define GFX_V_DISPLAY_TOTAL GENMASK(11, 0) ++ mutex_lock(&pcie->lock); + -+#define GFX_DISPLAY_ADDR 0x80 ++ bitmap_release_region(pcie->msi_irq_in_use, data->hwirq, ++ get_count_order(nr_irqs)); + -+enum { -+ VIDEO_CLK_25MHz = 0, -+ VIDEO_CLK_D1, -+ VIDEO_CLK_D2, -+ VIDEO_CLK_CRT1, -+ VIDEO_CLK_CRT2, -+ VIDEO_CLK_HPLL, -+ VIDEO_CLK_MPLL, -+ VIDEO_CLK_48MHz, ++ mutex_unlock(&pcie->lock); ++} ++ ++static const struct irq_domain_ops aspeed_msi_domain_ops = { ++ .alloc = aspeed_irq_msi_domain_alloc, ++ .free = aspeed_irq_msi_domain_free, +}; + - /* - * VIDEO_MODE_DETECT_DONE: a flag raised if signal lock - * VIDEO_RES_CHANGE: a flag raised if res_change work on-going -@@ -211,6 +263,7 @@ - * VIDEO_FRAME_INPRG: a flag raised if hw working on a frame - * VIDEO_STOPPED: a flag raised if device release - * VIDEO_CLOCKS_ON: a flag raised if clk is on -+ * VIDEO_BOUNDING_BOX: a flag raised if box-finding for partial-jpeg - */ - enum { - VIDEO_MODE_DETECT_DONE, -@@ -220,12 +273,14 @@ - VIDEO_FRAME_INPRG, - VIDEO_STOPPED, - VIDEO_CLOCKS_ON, -+ VIDEO_BOUNDING_BOX, - }; - - enum aspeed_video_format { - VIDEO_FMT_STANDARD = 0, - VIDEO_FMT_ASPEED, -- VIDEO_FMT_MAX = VIDEO_FMT_ASPEED -+ VIDEO_FMT_PARTIAL, -+ VIDEO_FMT_MAX = VIDEO_FMT_PARTIAL - }; - - // for VE_CTRL_CAPTURE_FMT -@@ -243,6 +298,11 @@ - void *virt; - }; - -+struct aspeed_video_box { -+ struct v4l2_rect box; -+ struct list_head link; ++static struct irq_chip aspeed_msi_irq_chip = { ++ .name = "PCIe MSI", ++ .irq_enable = pci_msi_unmask_irq, ++ .irq_disable = pci_msi_mask_irq, ++ .irq_mask = pci_msi_mask_irq, ++ .irq_unmask = pci_msi_unmask_irq, +}; + - struct aspeed_video_buffer { - struct vb2_v4l2_buffer vb; - struct list_head link; -@@ -262,6 +322,9 @@ - /* - * struct aspeed_video - driver data - * -+ * version: holds the version of aspeed SoC -+ * base: holds the base address of video engine -+ * dvi_base: holds the base address of DVI engine. For 2700 dvi support. - * res_work: holds the delayed_work for res-detection if unlock - * buffers: holds the list of buffer queued from user - * flags: holds the state of video -@@ -270,9 +333,11 @@ - * srcs: holds the buffer information for srcs - * jpeg: holds the buffer information for jpeg header - * bcd: holds the buffer information for bcd work -+ * dbg_src: holds the buffer information for debug input - * yuv420: a flag raised if JPEG subsampling is 420 - * format: holds the video format - * hq_mode: a flag raised if HQ is enabled. Only for VIDEO_FMT_ASPEED -+ * input: holds the video input - * frame_rate: holds the frame_rate - * jpeg_quality: holds jpeq's quality (0~11) - * jpeg_hq_quality: holds hq's quality (1~12) only if hq_mode enabled -@@ -281,11 +346,16 @@ - * frame_right: end position of video data in horizontal direction - * frame_top: start position of video data in vertical direction - * perf: holds the statistics primary for debugfs -+ * bounding_box: holds the video rect for partial-jpeg -+ * boxes: holds the list of video-rect info for each partial-jpeg - */ - struct aspeed_video { - void __iomem *base; -+ void __iomem *dvi_base; - struct clk *eclk; - struct clk *vclk; -+ struct clk *crt2clk; -+ struct reset_control *reset; - - struct device *dev; - struct v4l2_ctrl_handler ctrl_handler; -@@ -297,9 +367,15 @@ - struct vb2_queue queue; - struct video_device vdev; - struct mutex video_lock; /* v4l2 and videobuf2 lock */ -+ struct dentry *debugfs_entry; -+ int id; - -+ struct regmap *scu; -+ struct regmap *gfx; -+ u32 version; - u32 jpeg_mode; - u32 comp_size_read; -+ u32 compare_only; - - wait_queue_head_t wait; - spinlock_t lock; /* buffer list lock */ -@@ -307,15 +383,20 @@ - struct list_head buffers; - unsigned long flags; - unsigned int sequence; -+ struct workqueue_struct *rst_wq; -+ struct work_struct rst_work; - - unsigned int max_compressed_size; -+ struct aspeed_video_addr pool; - struct aspeed_video_addr srcs[2]; - struct aspeed_video_addr jpeg; - struct aspeed_video_addr bcd; -+ struct aspeed_video_addr dbg_src; - - bool yuv420; - enum aspeed_video_format format; - bool hq_mode; -+ enum aspeed_video_input input; - unsigned int frame_rate; - unsigned int jpeg_quality; - unsigned int jpeg_hq_quality; -@@ -326,28 +407,45 @@ - unsigned int frame_top; - - struct aspeed_video_perf perf; -+ struct v4l2_rect bounding_box; -+ struct list_head boxes; - }; - - #define to_aspeed_video(x) container_of((x), struct aspeed_video, v4l2_dev) - - struct aspeed_video_config { -+ u32 version; - u32 jpeg_mode; - u32 comp_size_read; -+ u32 compare_only; - }; - - static const struct aspeed_video_config ast2400_config = { -+ .version = 4, - .jpeg_mode = AST2400_VE_SEQ_CTRL_JPEG_MODE, - .comp_size_read = AST2400_VE_COMP_SIZE_READ_BACK, -+ .compare_only = 0, - }; - - static const struct aspeed_video_config ast2500_config = { -+ .version = 5, - .jpeg_mode = AST2500_VE_SEQ_CTRL_JPEG_MODE, - .comp_size_read = AST2400_VE_COMP_SIZE_READ_BACK, -+ .compare_only = 0, - }; - - 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, -+ .compare_only = AST2600_VE_CTRL_EN_COMPARE_ONLY, ++static struct msi_domain_info aspeed_msi_domain_info = { ++ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | ++ MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX), ++ .chip = &aspeed_msi_irq_chip, +}; ++#endif + -+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, -+ .compare_only = AST2600_VE_CTRL_EN_COMPARE_ONLY, - }; - - static const u32 aspeed_video_jpeg_header[ASPEED_VIDEO_JPEG_HEADER_SIZE] = { -@@ -484,9 +582,12 @@ - }; - - static const char * const format_str[] = {"Standard JPEG", -- "Aspeed JPEG"}; -+ "Aspeed JPEG", "Partial JPEG"}; -+static const char * const input_str[] = {"HOST VGA", "BMC GFX", "MEMORY", "DVI"}; - - static unsigned int debug; -+static unsigned int dual_flag; -+DECLARE_WAIT_QUEUE_HEAD(waitq); - - static bool aspeed_video_alloc_buf(struct aspeed_video *video, - struct aspeed_video_addr *addr, -@@ -495,6 +596,54 @@ - static void aspeed_video_free_buf(struct aspeed_video *video, - struct aspeed_video_addr *addr); - -+/** -+ * _make_addr - make address fit for ast2700 -+ * @addr: dma address for hardware to work -+ * -+ * Return: 32bit format of address -+ */ -+static inline u32 _make_addr(dma_addr_t addr) ++static void aspeed_pcie_irq_domain_free(struct aspeed_pcie *pcie) +{ -+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT -+ // In ast2700, it store higt byte[35:32] in low byte[3:0] -+ return (addr >> 32) | (u32)(addr); -+#else -+ return addr; ++ if (pcie->irq_domain) { ++ irq_domain_remove(pcie->irq_domain); ++ pcie->irq_domain = NULL; ++ } ++#ifdef CONFIG_PCI_MSI ++ if (pcie->msi_domain) { ++ irq_domain_remove(pcie->msi_domain); ++ pcie->msi_domain = NULL; ++ } ++ ++ if (pcie->dev_domain) { ++ irq_domain_remove(pcie->dev_domain); ++ pcie->dev_domain = NULL; ++ } +#endif +} + -+static void aspeed_video_support_vga_ctrl(struct aspeed_video *v, bool yes) ++static int aspeed_pcie_init_irq_domain(struct aspeed_pcie *pcie) +{ -+ u32 val = yes ? BIT(0) : 0; -+ u32 reg; -+ -+ if (!v || v->version < 6) -+ return; ++ struct device *dev = pcie->dev; ++ struct device_node *node = dev->of_node; ++ struct device_node *pcie_intc_node; ++ int ret; + -+ if (v->version == 7) -+ reg = (v->id == 1) ? 0x914 : 0x904; -+ else -+ reg = 0x104; ++ pcie_intc_node = of_get_next_child(node, NULL); ++ if (!pcie_intc_node) ++ return dev_err_probe(dev, -ENODEV, "No PCIe Intc node found\n"); + -+ regmap_update_bits(v->scu, reg, BIT(0), val); -+} ++ pcie->irq_domain = ++ irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, &aspeed_intx_domain_ops, pcie); ++ of_node_put(pcie_intc_node); ++ if (!pcie->irq_domain) { ++ ret = dev_err_probe(dev, -ENOMEM, "failed to get an INTx IRQ domain\n"); ++ goto err; ++ } + -+static void aspeed_video_set_vga_on(struct aspeed_video *v, bool on) -+{ -+ u32 val = on ? BIT(1) : 0; -+ u32 reg; ++ writel(0, pcie->reg + pcie->platform->reg_intx_en); ++ writel(~0, pcie->reg + pcie->platform->reg_intx_sts); + -+ if (!v || v->version < 6) -+ return; ++#ifdef CONFIG_PCI_MSI ++ pcie->dev_domain = ++ irq_domain_add_linear(NULL, MAX_MSI_HOST_IRQS, &aspeed_msi_domain_ops, pcie); ++ if (!pcie->dev_domain) { ++ ret = dev_err_probe(pcie->dev, -ENOMEM, "failed to create IRQ domain\n"); ++ goto err; ++ } + -+ if (v->version == 7) -+ reg = (v->id == 1) ? 0x914 : 0x904; -+ else -+ reg = 0x104; ++ pcie->msi_domain = pci_msi_create_irq_domain(dev_fwnode(pcie->dev), &aspeed_msi_domain_info, ++ pcie->dev_domain); ++ if (!pcie->msi_domain) { ++ ret = dev_err_probe(pcie->dev, -ENOMEM, "failed to create MSI domain\n"); ++ goto err; ++ } + -+ regmap_update_bits(v->scu, reg, BIT(1), val); ++ writel(~0, pcie->reg + pcie->platform->reg_msi_en); ++ writel(~0, pcie->reg + pcie->platform->reg_msi_en + 0x04); ++ writel(~0, pcie->reg + pcie->platform->reg_msi_sts); ++ writel(~0, pcie->reg + pcie->platform->reg_msi_sts + 0x04); ++#endif ++ return 0; ++err: ++ aspeed_pcie_irq_domain_free(pcie); ++ return ret; +} + - static void aspeed_video_init_jpeg_table(u32 *table, bool yuv420) - { - int i; -@@ -576,13 +725,58 @@ - p->duration); - } - -+static void aspeed_video_partial_jpeg_update_regs(struct aspeed_video *v) ++static void aspeed_pcie_port_init(struct aspeed_pcie *pcie) +{ -+ if (test_bit(VIDEO_BOUNDING_BOX, &v->flags)) { -+ aspeed_video_update(v, VE_SEQ_CTRL, -+ v->jpeg_mode, -+ VE_SEQ_CTRL_AUTO_COMP); -+ aspeed_video_update(v, VE_BCD_CTRL, 0, -+ VE_BCD_CTRL_EN_BCD); -+ aspeed_video_write(v, VE_COMP_WINDOW, -+ v->pix_fmt.width << 16 | -+ v->pix_fmt.height); -+ v4l2_dbg(1, debug, &v->v4l2_dev, -+ "%s: BCD enabled\n", __func__); -+ } else { -+ u32 scan_lines = aspeed_video_read(v, VE_SRC_SCANLINE_OFFSET); -+ u32 frame_count = aspeed_video_read(v, VE_COMP_FRAME_COUNT_READ_BACK); -+ u32 old_src_addr, new_src_addr; -+ dma_addr_t addr; -+ u32 offset; -+ -+ if (v->version >= 7) { -+ old_src_addr = (frame_count & 0x01) ? VE_SRC0_ADDR : VE_SRC1_ADDR; -+ new_src_addr = (frame_count & 0x01) ? VE_SRC1_ADDR : VE_SRC0_ADDR; -+ } else { -+ old_src_addr = VE_SRC0_ADDR; -+ new_src_addr = VE_SRC0_ADDR; -+ } -+ addr = aspeed_video_read(v, old_src_addr); ++ u32 link_sts = 0; + -+ aspeed_video_update(v, VE_SEQ_CTRL, -+ VE_SEQ_CTRL_AUTO_COMP, -+ v->jpeg_mode); -+ aspeed_video_update(v, VE_BCD_CTRL, -+ VE_BCD_CTRL_EN_BCD, 0); -+ aspeed_video_write(v, VE_COMP_WINDOW, -+ v->bounding_box.width << 16 | -+ v->bounding_box.height); ++ regmap_write(pcie->pciephy, PEHR_LOCK, PCIE_UNLOCK); + -+ offset = (scan_lines * v->bounding_box.top) + -+ ((256 * v->bounding_box.left) >> (v->yuv420 ? 4 : 3)); -+ aspeed_video_write(v, new_src_addr, addr + offset); -+ v4l2_dbg(1, debug, &v->v4l2_dev, -+ "%s: BCD disabled, frame#(%d) offset(0x%x)\n", __func__, frame_count, offset); ++ if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) { ++ regmap_write(pcie->pciephy, PEHR_GLOBAL, ++ RC_SYNC_RESET_DISABLE | ROOT_COMPLEX_ID(0x3) | PCIE_RC_SLOT_ENABLE); ++ regmap_write(pcie->pciephy, PEHR_MISC_10, 0xd7040022 | DATALINK_REPORT_CAPABLE); ++ regmap_write(pcie->pciephy, PEHR_MISC_14, ++ HOTPLUG_CAPABLE_ENABLE | HOTPLUG_SURPRISE_ENABLE | ++ ATTENTION_BUTTON_ENABLE); ++ } else { ++ regmap_write(pcie->pciephy, PEHR_GLOBAL, ROOT_COMPLEX_ID(0x3)); + } -+} -+ - static int aspeed_video_start_frame(struct aspeed_video *video) - { - dma_addr_t addr; - unsigned long flags; - struct aspeed_video_buffer *buf; - u32 seq_ctrl = aspeed_video_read(video, VE_SEQ_CTRL); -- bool bcd_buf_need = (video->format != VIDEO_FMT_STANDARD); - - if (video->v4l2_input_status) { - v4l2_dbg(1, debug, &video->v4l2_dev, "No signal; don't start frame\n"); -@@ -595,18 +789,14 @@ - return -EBUSY; - } - -- if (bcd_buf_need && !video->bcd.size) { -- if (!aspeed_video_alloc_buf(video, &video->bcd, -- VE_BCD_BUFF_SIZE)) { -- dev_err(video->dev, "Failed to allocate BCD buffer\n"); -- dev_err(video->dev, "don't start frame\n"); -- return -ENOMEM; -- } -- aspeed_video_write(video, VE_BCD_ADDR, video->bcd.dma); -- v4l2_dbg(1, debug, &video->v4l2_dev, "bcd addr(%pad) size(%d)\n", -- &video->bcd.dma, video->bcd.size); -- } else if (!bcd_buf_need && video->bcd.size) { -- aspeed_video_free_buf(video, &video->bcd); -+ if (video->input == VIDEO_INPUT_GFX) { -+ u32 val; + -+ // update input buffer address as gfx's -+ regmap_read(video->gfx, GFX_DISPLAY_ADDR, &val); -+ aspeed_video_write(video, VE_TGS_0, val); -+ } else if (video->input == VIDEO_INPUT_MEM) { -+ aspeed_video_write(video, VE_TGS_0, _make_addr(video->dbg_src.dma)); - } - - spin_lock_irqsave(&video->lock, flags); -@@ -624,15 +814,26 @@ - - aspeed_video_write(video, VE_COMP_PROC_OFFSET, 0); - aspeed_video_write(video, VE_COMP_OFFSET, 0); -- aspeed_video_write(video, VE_COMP_ADDR, addr); -+ aspeed_video_write(video, VE_COMP_ADDR, _make_addr(addr)); - - aspeed_video_update(video, VE_INTERRUPT_CTRL, 0, - VE_INTERRUPT_COMP_COMPLETE); - -- video->perf.last_sample = ktime_get(); -- -- aspeed_video_update(video, VE_SEQ_CTRL, 0, -- VE_SEQ_CTRL_TRIG_CAPTURE | VE_SEQ_CTRL_TRIG_COMP); -+ if (video->format == VIDEO_FMT_PARTIAL) { -+ aspeed_video_partial_jpeg_update_regs(video); -+ if (test_bit(VIDEO_BOUNDING_BOX, &video->flags)) { -+ video->perf.last_sample = ktime_get(); -+ seq_ctrl = VE_SEQ_CTRL_TRIG_CAPTURE | VE_SEQ_CTRL_TRIG_COMP; -+ aspeed_video_update(video, VE_CTRL, video->compare_only, video->compare_only); -+ } else { -+ seq_ctrl = VE_SEQ_CTRL_TRIG_COMP; -+ aspeed_video_update(video, VE_CTRL, video->compare_only, 0); -+ } -+ } else { -+ video->perf.last_sample = ktime_get(); -+ seq_ctrl = VE_SEQ_CTRL_TRIG_CAPTURE | VE_SEQ_CTRL_TRIG_COMP; ++ if (pcie->perst_rc_out) { ++ mdelay(100); ++ gpiod_set_value(pcie->perst_rc_out, 1); + } -+ aspeed_video_update(video, VE_SEQ_CTRL, 0, seq_ctrl); - - return 0; - } -@@ -660,6 +861,9 @@ - aspeed_video_write(video, VE_INTERRUPT_CTRL, 0); - aspeed_video_write(video, VE_INTERRUPT_STATUS, 0xffffffff); - -+ reset_control_assert(video->reset); -+ usleep_range(100, 200); + - /* Turn off the relevant clocks */ - clk_disable(video->eclk); - clk_disable(video->vclk); -@@ -676,7 +880,68 @@ - clk_enable(video->vclk); - clk_enable(video->eclk); - -+ mdelay(10); -+ reset_control_deassert(video->reset); ++ reset_control_deassert(pcie->perst); ++ mdelay(500); + - set_bit(VIDEO_CLOCKS_ON, &video->flags); ++ writel(PCIE_RX_DMA_EN | PCIE_RX_LINEAR | PCIE_RX_MSI_SEL | PCIE_RX_MSI_EN | ++ PCIE_Wait_RX_TLP_CLR | PCIE_RC_RX_ENABLE | PCIE_RC_ENABLE, ++ pcie->reg + H2X_DEV_CTRL); + -+ if (video->version >= 7) -+ queue_work(video->rst_wq, &video->rst_work); ++ writel(0x28, pcie->reg + H2X_DEV_TX_TAG); ++ ++ regmap_read(pcie->pciephy, PEHR_LINK, &link_sts); ++ if (link_sts & PCIE_LINK_STS) ++ dev_info(pcie->dev, "PCIE- Link up\n"); ++ else ++ dev_info(pcie->dev, "PCIE- Link down\n"); +} + -+static void aspeed_video_reset(struct aspeed_video *v) ++static ssize_t hotplug_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) +{ -+ int rc; -+ u32 val; ++ struct aspeed_pcie *pcie = dev_get_drvdata(dev); + -+ reset_control_assert(v->reset); -+ rc = reset_control_status(v->reset); -+ if (rc == 0) { -+ /* 2700 has 2 VE, but only 1 reset. To have reset work, we need -+ * to notify the other VE if reset is not asserted. -+ */ -+ val = 1 << (v->id ^ 1); -+ dual_flag |= val; -+ v4l2_dbg(2, debug, &v->v4l2_dev, "%s: reset not asserted, needs another VE(%x)\n", __func__, val); -+ wake_up_all(&waitq); -+ rc = wait_event_interruptible(waitq, (dual_flag & val) != val); -+ if (rc) -+ v4l2_dbg(2, debug, &v->v4l2_dev, "%s: another VE done, dual_flag(%d)\n", __func__, dual_flag); ++ pcie->hotplug_event = 1; ++ ++ if (of_device_is_compatible(pcie->dev->of_node, "aspeed,ast2700-pcie")) { ++ regmap_write_bits(pcie->pciephy, PEHR_MISC_1B8, SW_ATT_BTN, SW_ATT_BTN); ++ regmap_clear_bits(pcie->pciephy, PEHR_MISC_1B8, SW_ATT_BTN); + } + -+ usleep_range(100, 200); -+ reset_control_deassert(v->reset); -+ udelay(1); ++ return len; +} + -+/* -+ * aspeed_video_rst_worker: This is a work to wait event from the other VE to -+ * do full function reset because 2700's 2 VE share 1 reset line. When there -+ * is one VE wants reset, both VE needs to do it. -+ * -+ */ -+static void aspeed_video_rst_worker(struct work_struct *work) ++static DEVICE_ATTR_WO(hotplug); ++ ++static void aspeed_pcie_reset_work(struct work_struct *work) +{ -+ struct aspeed_video *v = -+ container_of(work, struct aspeed_video, rst_work); -+ int rc; ++ struct aspeed_pcie *pcie = ++ container_of(work, typeof(*pcie), rst_dwork.work); ++ struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); ++ struct pci_bus *parent = host->bus; ++ struct pci_dev *dev, *temp; ++ u32 link_sts = 0; ++ u16 command; + -+ rc = wait_event_timeout(waitq, -+ (dual_flag & (1 << v->id)), -+ INVALID_RESOLUTION_DELAY); -+ if (rc) { -+ v4l2_dbg(2, debug, &v->v4l2_dev, "%s: dual_flag(%x)\n", __func__, dual_flag); -+ dual_flag = 0; -+ set_bit(VIDEO_RES_CHANGE, &v->flags); -+ clear_bit(VIDEO_FRAME_INPRG, &v->flags); -+ schedule_delayed_work(&v->res_work, 0); -+ wait_event_interruptible(v->wait, -+ !test_bit(VIDEO_RES_CHANGE, &v->flags)); -+ v4l2_dbg(2, debug, &v->v4l2_dev, "%s: rst and clear, %d\n", __func__, rc); -+ } ++ pci_lock_rescan_remove(); + -+ if (test_bit(VIDEO_CLOCKS_ON, &v->flags)) -+ queue_work(v->rst_wq, &v->rst_work); - } - - static void aspeed_video_bufs_done(struct aspeed_video *video, -@@ -684,11 +949,18 @@ - { - unsigned long flags; - struct aspeed_video_buffer *buf; -+ struct aspeed_video_box *box, *tmp; - - spin_lock_irqsave(&video->lock, flags); - list_for_each_entry(buf, &video->buffers, link) - vb2_buffer_done(&buf->vb.vb2_buf, state); - INIT_LIST_HEAD(&video->buffers); ++ list_for_each_entry_safe_reverse(dev, temp, &parent->devices, ++ bus_list) { ++ pci_dev_get(dev); ++ pci_stop_and_remove_bus_device(dev); ++ /* ++ * Ensure that no new Requests will be generated from ++ * the device. ++ */ ++ pci_read_config_word(dev, PCI_COMMAND, &command); ++ command &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_SERR); ++ command |= PCI_COMMAND_INTX_DISABLE; ++ pci_write_config_word(dev, PCI_COMMAND, command); ++ pci_dev_put(dev); ++ } + -+ list_for_each_entry_safe(box, tmp, &video->boxes, link) { -+ list_del(&box->link); -+ kfree(box); ++ /* ++ * With perst_rc_out GPIO, the perst will only affect our PCIe controller, so it only ++ * needs to stay low for 1ms. ++ * Without perst_rc_out GPIO, the perst will affect external devices, so it needs to ++ * follow the spec and stay low for at least 100ms. ++ */ ++ reset_control_assert(pcie->perst); ++ if (pcie->perst_rc_out) { ++ gpiod_set_value(pcie->perst_rc_out, 0); ++ mdelay(1); ++ } else { ++ mdelay(100); + } -+ INIT_LIST_HEAD(&video->boxes); - spin_unlock_irqrestore(&video->lock, flags); - } - -@@ -701,12 +973,96 @@ - - video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; - -- aspeed_video_off(video); -+ aspeed_video_write(video, VE_INTERRUPT_CTRL, 0); -+ aspeed_video_write(video, VE_INTERRUPT_STATUS, 0xffffffff); - aspeed_video_bufs_done(video, VB2_BUF_STATE_ERROR); - - schedule_delayed_work(&video->res_work, delay); - } - -+static inline bool _box_data_changed(struct aspeed_video *v, u8 data) -+{ -+ if (v->version >= 6) -+ return ((data & 0xf) != 0xf); ++ reset_control_deassert(pcie->perst); ++ if (pcie->perst_rc_out) { ++ mdelay(100); ++ gpiod_set_value(pcie->perst_rc_out, 1); ++ } ++ mdelay(10); + -+ return ((data & 0xf) == 0xf); ++ regmap_read(pcie->pciephy, PEHR_LINK, &link_sts); ++ if (link_sts & PCIE_LINK_STS) ++ dev_info(pcie->dev, "PCIE- Link up\n"); ++ else ++ dev_info(pcie->dev, "PCIE- Link down\n"); ++ ++ pci_rescan_bus(host->bus); ++ pci_unlock_rescan_remove(); +} + -+static void aspeed_video_get_bounding_box(struct aspeed_video *v, -+ struct v4l2_rect *box) ++static irqreturn_t pcie_rst_irq_handler(int irq, void *dev_id) +{ -+ u16 min_x, min_y, max_x, max_y; -+ u16 w, h, i, j; -+ u32 bytesperline; -+ u8 mb_shift = v->yuv420 ? 4 : 3; -+ u8 *bcd_buf = v->bcd.virt; ++ struct aspeed_pcie *pcie = dev_id; + -+ if (!bcd_buf) { -+ box->left = 0; -+ box->top = 0; -+ box->width = v->pix_fmt.width; -+ box->height = v->pix_fmt.width; -+ v4l2_dbg(1, debug, &v->v4l2_dev, "%s: bcd buf not ready yet\n", __func__); -+ return; -+ } ++ schedule_delayed_work(&pcie->rst_dwork, 0); + -+ w = v->pix_fmt.width >> mb_shift; -+ h = v->pix_fmt.height >> mb_shift; -+ v4l2_dbg(1, debug, &v->v4l2_dev, "%s: macrobox_shift(%d) size (%d * %d)\n", -+ __func__, mb_shift, w, h); ++ return IRQ_HANDLED; ++} + -+ min_x = 0x3ff; -+ min_y = 0x3ff; -+ max_x = 0; -+ max_y = 0; ++static int aspeed_ast2600_setup(struct platform_device *pdev) ++{ ++ struct aspeed_pcie *pcie = platform_get_drvdata(pdev); ++ struct device *dev = pcie->dev; ++ int ret; + -+ for (j = 0; j < h; j++) { -+ bytesperline = w * j; -+ for (i = 0; i < w; i++) { -+ if (_box_data_changed(v, *(bcd_buf + bytesperline + i))) { -+ min_x = min(i, min_x); -+ max_x = max(i, max_x); -+ min_y = min(j, min_y); -+ max_y = max(j, max_y); -+ -+ // skip line if max_x can't be bigger -+ if (max_x == w) -+ i = w; -+ // skip the pixels between min_x ~ max_x -+ if (max_x > min_x && i > min_x && i < max_x) -+ i = max_x; -+ } -+ } ++ if (pcie->host_bus_num != 0x80) { ++ dev_err(dev, "AST2600 only supports to start bus number 0x80\n"); ++ return -EINVAL; + } -+ v4l2_dbg(1, debug, &v->v4l2_dev, -+ "%s: left %d right %d top %d bottom %d\n", __func__, -+ min_x, max_x, min_y, max_y); + -+ // clear bcd flag -+ if (v->version < 6) -+ memset(bcd_buf, 0x01, (w * h)); ++ pcie->ahbc = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,ahbc"); ++ if (IS_ERR(pcie->ahbc)) ++ return dev_err_probe(dev, PTR_ERR(pcie->ahbc), "failed to map ahbc base\n"); + -+ // use full size every 8 frames -+ if (IS_ALIGNED(v->sequence, 8)) { -+ min_x = 0; -+ max_x = w - 1; -+ min_y = 0; -+ max_y = h - 1; -+ } else if (min_x > max_x || min_y > max_y || max_x > w || max_y > h) { -+ memset(box, 0, sizeof(*box)); -+ v4l2_dbg(1, debug, &v->v4l2_dev, "box not found\n"); -+ return; -+ } ++ reset_control_assert(pcie->h2xrst); ++ mdelay(5); ++ reset_control_deassert(pcie->h2xrst); + -+ box->left = min_x << mb_shift; -+ box->top = min_y << mb_shift; -+ box->width = (max_x + 1 - min_x) << mb_shift; -+ box->height = (max_y + 1 - min_y) << mb_shift; -+ v4l2_dbg(1, debug, &v->v4l2_dev, -+ "%s: x: %d, y: %d, w: %d , h: %d\n", __func__, -+ box->left, box->top, box->width, box->height); -+} ++ regmap_write(pcie->ahbc, AHBC_KEY, AHBC_UNLOCK); ++ regmap_update_bits(pcie->ahbc, AHBC_ADDR_MAPPING, PCIE_RC_MEMORY_EN, PCIE_RC_MEMORY_EN); ++ regmap_write(pcie->ahbc, AHBC_KEY, 0x1); + - static void aspeed_video_swap_src_buf(struct aspeed_video *v) - { - if (v->format == VIDEO_FMT_STANDARD) -@@ -716,24 +1072,100 @@ - if (IS_ALIGNED(v->sequence, 8)) - memset((u8 *)v->bcd.virt, 0x00, VE_BCD_BUFF_SIZE); - -+ // 2700's new design will automatically swap src at each operation -+ if (v->version > 6 && v->format == VIDEO_FMT_ASPEED) -+ return; ++ regmap_write(pcie->cfg, H2X_AHB_ADDR_CONFIG0, 0xe0006000); ++ regmap_write(pcie->cfg, H2X_AHB_ADDR_CONFIG1, 0); ++ regmap_write(pcie->cfg, H2X_AHB_ADDR_CONFIG2, ~0); + - if (v->sequence & 0x01) { -- aspeed_video_write(v, VE_SRC0_ADDR, v->srcs[1].dma); -- aspeed_video_write(v, VE_SRC1_ADDR, v->srcs[0].dma); -+ aspeed_video_write(v, VE_SRC0_ADDR, _make_addr(v->srcs[1].dma)); -+ aspeed_video_write(v, VE_SRC1_ADDR, _make_addr(v->srcs[0].dma)); - } else { -- aspeed_video_write(v, VE_SRC0_ADDR, v->srcs[0].dma); -- 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)); ++ regmap_write(pcie->cfg, H2X_CTRL, H2X_BRIDGE_EN); ++ ++ aspeed_pcie_port_init(pcie); ++ ++ pcie->host->ops = &aspeed_ast2600_pcie_ops; ++ ++ pcie->perst_ep_in = devm_gpiod_get_optional(pcie->dev, "perst-ep-in", GPIOD_IN); ++ if (pcie->perst_ep_in) { ++ gpiod_set_debounce(pcie->perst_ep_in, 100); ++ irq_set_irq_type(gpiod_to_irq(pcie->perst_ep_in), IRQ_TYPE_EDGE_BOTH); ++ ret = devm_request_irq(pcie->dev, gpiod_to_irq(pcie->perst_ep_in), ++ pcie_rst_irq_handler, IRQF_SHARED, "PERST monitor", pcie); ++ if (ret) ++ return dev_err_probe(pcie->dev, ret, "Failed to request gpio irq\n"); ++ INIT_DELAYED_WORK(&pcie->rst_dwork, aspeed_pcie_reset_work); + } ++ pcie->perst_owner = ++ devm_gpiod_get_optional(pcie->dev, "perst-owner", GPIOD_OUT_HIGH); ++ ++ return 0; +} + -+static void aspeed_video_frame_done_handler(struct aspeed_video *video, -+ bool buf_done) ++static int aspeed_ast2700_setup(struct platform_device *pdev) +{ -+ struct aspeed_video_buffer *buf; -+ bool empty = true; -+ u32 frame_size; ++ struct aspeed_pcie *pcie = platform_get_drvdata(pdev); ++ struct device *dev = pcie->dev; ++ u32 cfg_val; + -+ if (!buf_done) -+ return; ++ reset_control_assert(pcie->perst); + -+ spin_lock(&video->lock); -+ clear_bit(VIDEO_FRAME_INPRG, &video->flags); -+ buf = list_first_entry_or_null(&video->buffers, -+ struct aspeed_video_buffer, -+ link); -+ if (buf) { -+ frame_size = aspeed_video_read(video, -+ video->comp_size_read); -+ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, frame_size); ++ regmap_write(pcie->pciephy, PEHR_MISC_70, 0xa00c0); ++ regmap_write(pcie->pciephy, PEHR_MISC_78, 0x80030); ++ regmap_write(pcie->pciephy, PEHR_MISC_58, LOCAL_SCALE_SUP); + -+ /* -+ * VIDEO_FMT_ASPEED requires continuous update. -+ * On the contrary, standard jpeg can keep last buffer -+ * to always have the latest result. -+ */ -+ if (video->format != VIDEO_FMT_ASPEED && -+ list_is_last(&buf->link, &video->buffers)) { -+ empty = false; -+ v4l2_dbg(1, debug, &video->v4l2_dev, "skip to keep last frame updated\n"); -+ } else { -+ buf->vb.vb2_buf.timestamp = ktime_get_ns(); -+ buf->vb.sequence = video->sequence++; -+ buf->vb.field = V4L2_FIELD_NONE; -+ vb2_buffer_done(&buf->vb.vb2_buf, -+ VB2_BUF_STATE_DONE); -+ list_del(&buf->link); -+ empty = list_empty(&video->buffers); -+ if (video->format == VIDEO_FMT_PARTIAL) { -+ struct aspeed_video_box *box = -+ kmalloc(sizeof(struct aspeed_video_box), -+ GFP_KERNEL); ++ regmap_update_bits(pcie->cfg, SCU_60, ++ RC_E2M_PATH_EN | RC_H2XS_PATH_EN | RC_H2XD_PATH_EN | RC_H2XX_PATH_EN | ++ RC_UPSTREAM_MEM_EN, ++ RC_E2M_PATH_EN | RC_H2XS_PATH_EN | RC_H2XD_PATH_EN | RC_H2XX_PATH_EN | ++ RC_UPSTREAM_MEM_EN); ++ regmap_write(pcie->cfg, SCU_64, 0xff00ff00); ++ regmap_write(pcie->cfg, SCU_70, 0); ++ regmap_write(pcie->cfg, SCU_78, (pcie->domain == 1) ? BIT(31) : 0); + -+ box->box = video->bounding_box; -+ list_add_tail(&box->link, &video->boxes); -+ } -+ } - } -+ spin_unlock(&video->lock); ++ reset_control_assert(pcie->h2xrst); ++ mdelay(10); ++ reset_control_deassert(pcie->h2xrst); + -+ aspeed_video_swap_src_buf(video); ++ regmap_write(pcie->pciephy, PEHR_MISC_5C, 0x40000000); ++ regmap_read(pcie->pciephy, PEHR_MISC_60, &cfg_val); ++ regmap_write(pcie->pciephy, PEHR_MISC_60, ++ (cfg_val & ~PORT_TPYE) | FIELD_PREP(PORT_TPYE, PORT_TYPE_ROOT)); + -+ if (test_bit(VIDEO_STREAMING, &video->flags) && !empty && -+ video->input != VIDEO_INPUT_MEM) { -+ set_bit(VIDEO_BOUNDING_BOX, &video->flags); -+ aspeed_video_start_frame(video); ++ writel(0, pcie->reg + H2X_CTRL); ++ writel(H2X_BRIDGE_EN | H2X_BRIDGE_DIRECT_EN, pcie->reg + H2X_CTRL); ++ ++ /* The BAR mapping: ++ * CPU Node0(domain 0): 0x60000000 ++ * CPU Node1(domain 1): 0x80000000 ++ * IO (domain 2): 0xa0000000 ++ */ ++ writel(0x60000000 + (0x20000000 * pcie->domain), pcie->reg + H2X_REMAP_DIRECT_ADDR); ++ ++ /* Prepare for 64-bit BAR pref */ ++ writel(0x3, pcie->reg + H2X_REMAP_PREF_ADDR); ++ ++ reset_control_deassert(pcie->perst); ++ if (pcie->perst_rc_out) ++ gpiod_set_value(pcie->perst_rc_out, 1); ++ mdelay(1000); ++ ++ pcie->host->ops = &aspeed_ast2700_pcie_ops; ++ ++ if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) { ++ regmap_write_bits(pcie->pciephy, PEHR_MISC_44, ENABLE_SLOT_CAP, ++ ENABLE_SLOT_CAP); ++ regmap_write(pcie->pciephy, PEHR_MISC_3C, ++ HOTPLUG_CAPABLE_ENABLE | HOTPLUG_SURPRISE_ENABLE | ++ ATTENTION_BUTTON_ENABLE); ++ regmap_write_bits(pcie->pciephy, PEHR_MISC_38, ++ DATALINK_REPORT_CAP, DATALINK_REPORT_CAP); + } ++ ++ if (!aspeed_ast2700_get_link(pcie)) ++ dev_info(dev, "PCIe Link DOWN"); ++ else ++ dev_info(dev, "PCIe Link UP"); ++ ++ return 0; +} + -+static irqreturn_t aspeed_video_thread_irq(int irq, void *arg) ++static int aspeed_pcie_probe(struct platform_device *pdev) +{ -+ struct aspeed_video *v = arg; ++ struct device *dev = &pdev->dev; ++ struct pci_host_bridge *host; ++ struct aspeed_pcie *pcie; ++ struct device_node *node = dev->of_node; ++ struct resource bus_range; ++ const void *md = of_device_get_match_data(dev); ++ int irq, ret; + -+ aspeed_video_get_bounding_box(v, &v->bounding_box); ++ if (!md) ++ return -ENODEV; + -+ if (v->bounding_box.width && v->bounding_box.height) -+ clear_bit(VIDEO_BOUNDING_BOX, &v->flags); -+ else -+ set_bit(VIDEO_BOUNDING_BOX, &v->flags); ++ host = devm_pci_alloc_host_bridge(dev, sizeof(*pcie)); ++ if (!host) ++ return -ENOMEM; + -+ aspeed_video_start_frame(v); ++ pcie = pci_host_bridge_priv(host); ++ pcie->dev = dev; ++ pcie->tx_tag = 0; ++ platform_set_drvdata(pdev, pcie); + -+ return IRQ_HANDLED; - } - - static irqreturn_t aspeed_video_irq(int irq, void *arg) - { - struct aspeed_video *video = arg; - u32 sts = aspeed_video_read(video, VE_INTERRUPT_STATUS); -+ bool get_box = false; - -- /* -- * Hardware sometimes asserts interrupts that we haven't actually -- * enabled; ignore them if so. -- */ -+ aspeed_video_write(video, VE_INTERRUPT_STATUS, sts); - 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 +1187,6 @@ - if (test_bit(VIDEO_RES_DETECT, &video->flags)) { - aspeed_video_update(video, VE_INTERRUPT_CTRL, - VE_INTERRUPT_MODE_DETECT, 0); -- aspeed_video_write(video, VE_INTERRUPT_STATUS, -- VE_INTERRUPT_MODE_DETECT); - sts &= ~VE_INTERRUPT_MODE_DETECT; - set_bit(VIDEO_MODE_DETECT_DONE, &video->flags); - wake_up_interruptible_all(&video->wait); -@@ -772,41 +1202,13 @@ - } - - if (sts & VE_INTERRUPT_COMP_COMPLETE) { -- struct aspeed_video_buffer *buf; -- bool empty = true; -- u32 frame_size = aspeed_video_read(video, -- video->comp_size_read); -- -- update_perf(&video->perf); -- -- spin_lock(&video->lock); -- clear_bit(VIDEO_FRAME_INPRG, &video->flags); -- buf = list_first_entry_or_null(&video->buffers, -- struct aspeed_video_buffer, -- link); -- if (buf) { -- vb2_set_plane_payload(&buf->vb.vb2_buf, 0, frame_size); -+ bool frame_done = false; - -- /* -- * aspeed_jpeg requires continuous update. -- * On the contrary, standard jpeg can keep last buffer -- * to always have the latest result. -- */ -- if (video->format == VIDEO_FMT_STANDARD && -- list_is_last(&buf->link, &video->buffers)) { -- empty = false; -- v4l2_dbg(1, debug, &video->v4l2_dev, "skip to keep last frame updated\n"); -- } else { -- buf->vb.vb2_buf.timestamp = ktime_get_ns(); -- buf->vb.sequence = video->sequence++; -- buf->vb.field = V4L2_FIELD_NONE; -- vb2_buffer_done(&buf->vb.vb2_buf, -- VB2_BUF_STATE_DONE); -- list_del(&buf->link); -- empty = list_empty(&video->buffers); -- } -- } -- spin_unlock(&video->lock); -+ if (video->format != VIDEO_FMT_PARTIAL) -+ frame_done = true; -+ else if (!test_bit(VIDEO_BOUNDING_BOX, &video->flags) && -+ video->bounding_box.width && video->bounding_box.height) -+ frame_done = true; - - aspeed_video_update(video, VE_SEQ_CTRL, - VE_SEQ_CTRL_TRIG_CAPTURE | -@@ -814,17 +1216,60 @@ - VE_SEQ_CTRL_TRIG_COMP, 0); - aspeed_video_update(video, VE_INTERRUPT_CTRL, - VE_INTERRUPT_COMP_COMPLETE, 0); -- aspeed_video_write(video, VE_INTERRUPT_STATUS, -- VE_INTERRUPT_COMP_COMPLETE); - sts &= ~VE_INTERRUPT_COMP_COMPLETE; - -- aspeed_video_swap_src_buf(video); -+ if (frame_done) { -+ update_perf(&video->perf); -+ aspeed_video_frame_done_handler(video, frame_done); -+ } else { -+ get_box = true; -+ } ++ pcie->platform = md; ++ pcie->host = host; ++ ++ if (of_pci_parse_bus_range(node, &bus_range)) { ++ dev_warn(dev, "Failed to parse bus range\n"); ++ pcie->host_bus_num = 0; + } - -- if (test_bit(VIDEO_STREAMING, &video->flags) && !empty) -- aspeed_video_start_frame(video); -+ return get_box ? IRQ_WAKE_THREAD : IRQ_HANDLED; -+} ++ pcie->host_bus_num = bus_range.start; + -+static irqreturn_t aspeed_video_md_irq(int irq, void *arg) -+{ -+ struct aspeed_video *video = arg; -+ u32 sts; ++ pcie->reg = devm_platform_ioremap_resource(pdev, 0); + -+ sts = readl(video->dvi_base + VE_INTERRUPT_STATUS); -+ writel(sts, video->dvi_base + VE_INTERRUPT_STATUS); -+ sts &= readl(video->dvi_base + VE_INTERRUPT_CTRL); ++ pcie->domain = of_get_pci_domain_nr(node); + -+ v4l2_dbg(2, debug, &video->v4l2_dev, "dvi irq sts=%#x %s%s\n", sts, -+ sts & VE_INTERRUPT_MODE_DETECT_WD ? ", unlock" : "", -+ sts & VE_INTERRUPT_MODE_DETECT ? ", lock" : ""); ++ pcie->cfg = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,pciecfg"); ++ if (IS_ERR(pcie->cfg)) ++ return dev_err_probe(dev, PTR_ERR(pcie->cfg), "Failed to map pciecfg base\n"); + -+ if (sts & VE_INTERRUPT_MODE_DETECT_WD) { -+ writel(0, video->dvi_base + VE_INTERRUPT_CTRL); -+ writel(0xffffffff, video->dvi_base + VE_INTERRUPT_STATUS); -+ aspeed_video_irq_res_change(video, 0); -+ return IRQ_HANDLED; - } - -- return sts ? IRQ_NONE : IRQ_HANDLED; -+ if (sts & VE_INTERRUPT_MODE_DETECT) { -+ if (test_bit(VIDEO_RES_DETECT, &video->flags)) { -+ aspeed_video_update(video, VE_INTERRUPT_CTRL, -+ VE_INTERRUPT_MODE_DETECT, 0); -+ sts &= ~VE_INTERRUPT_MODE_DETECT; -+ set_bit(VIDEO_MODE_DETECT_DONE, &video->flags); -+ wake_up_interruptible_all(&video->wait); -+ } else { -+ /* -+ * Signal acquired while NOT doing resolution -+ * detection; reset the engine and re-initialize -+ */ -+ writel(0, video->dvi_base + VE_INTERRUPT_CTRL); -+ writel(0xffffffff, video->dvi_base + VE_INTERRUPT_STATUS); -+ aspeed_video_irq_res_change(video, -+ RESOLUTION_CHANGE_DELAY); -+ return IRQ_HANDLED; -+ } ++ pcie->pciephy = syscon_regmap_lookup_by_phandle(node, "aspeed,pciephy"); ++ if (IS_ERR(pcie->pciephy)) ++ return dev_err_probe(dev, PTR_ERR(pcie->pciephy), "Failed to map pciephy base\n"); ++ ++ pcie->h2xrst = devm_reset_control_get_exclusive(dev, "h2x"); ++ if (IS_ERR(pcie->h2xrst)) ++ return dev_err_probe(dev, PTR_ERR(pcie->h2xrst), "Failed to get h2x reset\n"); ++ ++ pcie->perst = devm_reset_control_get_exclusive(dev, "perst"); ++ if (IS_ERR(pcie->perst)) ++ return dev_err_probe(dev, PTR_ERR(pcie->perst), "Failed to get perst reset\n"); ++ ++ pcie->perst_rc_out = devm_gpiod_get_optional(dev, "perst-rc-out", ++ GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); ++ ++ ret = devm_mutex_init(dev, &pcie->lock); ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to init mutex\n"); ++ ++ ret = pcie->platform->setup(pdev); ++ if (ret) ++ return dev_err_probe(dev, ret, "Failed to setup PCIe RC\n"); ++ ++ if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) { ++ ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_hotplug.attr); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, "unable to create sysfs interface\n"); + } + -+ return IRQ_HANDLED; - } - - static void aspeed_video_check_and_set_polarity(struct aspeed_video *video) -@@ -896,7 +1341,7 @@ - - /* - * Get the minimum HW-supported compression buffer size for the frame size. -- * Assume worst-case JPEG compression size is 1/8 raw size. This should be -+ * Assume worst-case JPEG compression size is 1/4 raw size. This should be - * plenty even for maximum quality; any worse and the engine will simply return - * incomplete JPEGs. - */ -@@ -908,7 +1353,7 @@ - unsigned int size; - const unsigned int num_compression_packets = 4; - const unsigned int compression_packet_size = 1024; -- const unsigned int max_compressed_size = frame_size / 2; /* 4bpp / 8 */ -+ const unsigned int max_compressed_size = frame_size; /* 4bpp / 4 */ - - video->max_compressed_size = UINT_MAX; - -@@ -929,6 +1374,7 @@ - aspeed_video_write(video, VE_STREAM_BUF_SIZE, - compression_buffer_size_reg); - -+ video->max_compressed_size = round_up(max_compressed_size, 0x10000); - v4l2_dbg(1, debug, &video->v4l2_dev, "Max compressed size: %#x\n", - video->max_compressed_size); - } -@@ -1026,9 +1472,23 @@ - } - } - -+static void aspeed_video_get_resolution_gfx(struct aspeed_video *video, -+ struct v4l2_bt_timings *det) -+{ -+ u32 h_val, v_val; ++ host->sysdata = pcie; + -+ regmap_read(video->gfx, GFX_H_DISPLAY, &h_val); -+ regmap_read(video->gfx, GFX_V_DISPLAY, &v_val); ++ ret = aspeed_pcie_init_irq_domain(pcie); ++ if (ret) ++ return dev_err_probe(dev, ret, "Failed to initialize IntX/MSI domain\n"); + -+ det->width = FIELD_GET(GFX_H_DISPLAY_DE, h_val) + 1; -+ det->height = FIELD_GET(GFX_V_DISPLAY_DE, v_val) + 1; -+ video->v4l2_input_status = 0; -+} ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) ++ return dev_err_probe(dev, irq, "Failed to get IRQ\n"); + - #define res_check(v) test_and_clear_bit(VIDEO_MODE_DETECT_DONE, &(v)->flags) - --static void aspeed_video_get_resolution(struct aspeed_video *video) -+static void aspeed_video_get_resolution_vga(struct aspeed_video *video, -+ struct v4l2_bt_timings *det) - { - bool invalid_resolution = true; - int rc; -@@ -1036,7 +1496,6 @@ - u32 mds; - u32 src_lr_edge; - u32 src_tb_edge; -- struct v4l2_bt_timings *det = &video->detected_timings; - - det->width = MIN_WIDTH; - det->height = MIN_HEIGHT; -@@ -1107,20 +1566,51 @@ - return; - } - -+ if (video->input == VIDEO_INPUT_DVI && video->version == 6) -+ video->frame_right -= 1; ++ ret = devm_request_irq(dev, irq, aspeed_pcie_intr_handler, IRQF_SHARED, ++ dev_name(dev), pcie); ++ if (ret) ++ return dev_err_probe(dev, ret, "Failed to request IRQ\n"); + - det->height = (video->frame_bottom - video->frame_top) + 1; - det->width = (video->frame_right - video->frame_left) + 1; - video->v4l2_input_status = 0; - - aspeed_video_get_timings(video, det); - -- /* -- * Enable mode-detect watchdog, resolution-change watchdog and -- * automatic compression after frame capture. -- */ -+ /* Enable mode-detect watchdog, resolution-change watchdog */ - aspeed_video_update(video, VE_INTERRUPT_CTRL, 0, - VE_INTERRUPT_MODE_DETECT_WD); -- aspeed_video_update(video, VE_SEQ_CTRL, 0, -- VE_SEQ_CTRL_AUTO_COMP | VE_SEQ_CTRL_EN_WATCHDOG); -+ aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_EN_WATCHDOG); -+} ++ pcie->clock = clk_get(dev, NULL); ++ if (IS_ERR(pcie->clock)) ++ return dev_err_probe(dev, PTR_ERR(pcie->clock), "Failed to request clock\n"); + -+/* -+ * For ast2700 only. Due to hw design, the timing detection of DVI is -+ * in io-die. Thus, we need to use another hw to do this job. -+ */ -+static void aspeed_video_get_resolution_dvi(struct aspeed_video *video, -+ struct v4l2_bt_timings *det) -+{ -+ void *base = video->base; ++ ret = clk_prepare_enable(pcie->clock); ++ if (ret) { ++ clk_put(pcie->clock); ++ return dev_err_probe(dev, ret, "Failed to enable the clock\n"); ++ } + -+ video->base = video->dvi_base; -+ aspeed_video_get_resolution_vga(video, det); -+ video->base = base; ++ return pci_host_probe(host); +} + -+static void aspeed_video_get_resolution(struct aspeed_video *video) ++static void aspeed_pcie_remove(struct platform_device *pdev) +{ -+ struct v4l2_bt_timings *det = &video->detected_timings; ++ struct aspeed_pcie *pcie = platform_get_drvdata(pdev); + -+ // if input is MEM, leave resolution decided by user through set_dv_timings -+ if (video->input == VIDEO_INPUT_MEM) { -+ video->v4l2_input_status = 0; -+ return; ++ if (pcie->clock) { ++ clk_disable_unprepare(pcie->clock); ++ clk_put(pcie->clock); + } + -+ if (video->input == VIDEO_INPUT_GFX) -+ aspeed_video_get_resolution_gfx(video, det); -+ else if (video->input == VIDEO_INPUT_DVI && video->version == 7) -+ aspeed_video_get_resolution_dvi(video, det); -+ else -+ aspeed_video_get_resolution_vga(video, det); - - v4l2_dbg(1, debug, &video->v4l2_dev, "Got resolution: %dx%d\n", - det->width, det->height); -@@ -1130,6 +1620,7 @@ - { - 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); - - /* Set capture/compression frame sizes */ - aspeed_video_calc_compressed_size(video, size); -@@ -1156,7 +1647,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) */ -- if (size < DIRECT_FETCH_THRESHOLD) { -+ if (video->input == VIDEO_INPUT_VGA && size < DIRECT_FETCH_THRESHOLD && -+ is_sync_mode_ok) { - 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 +1662,50 @@ - aspeed_video_update(video, VE_CTRL, - VE_CTRL_INT_DE | VE_CTRL_DIRECT_FETCH, - VE_CTRL_INT_DE); -+ } else if (video->input == VIDEO_INPUT_DVI) { -+ v4l2_dbg(1, debug, &video->v4l2_dev, "Capture: Sync Mode for external source\n"); -+ aspeed_video_update(video, VE_CTRL, -+ VE_CTRL_INT_DE | VE_CTRL_DIRECT_FETCH, -+ 0); - } else { -+ u32 ctrl, val, bpp; -+ - v4l2_dbg(1, debug, &video->v4l2_dev, "Capture: Direct Mode\n"); -+ ctrl = VE_CTRL_DIRECT_FETCH; -+ if (video->input == VIDEO_INPUT_GFX) { -+ regmap_read(video->gfx, GFX_CTRL, &val); -+ bpp = FIELD_GET(GFX_CTRL_FMT, val) ? 32 : 16; -+ if (bpp == 16) -+ ctrl |= VE_CTRL_INT_DE; -+ aspeed_video_write(video, VE_TGS_1, act->width * (bpp >> 3)); -+ } else { -+ // stride should be the same with capture window width -+ val = aspeed_video_read(video, VE_CAP_WINDOW) >> 16; -+ aspeed_video_write(video, VE_TGS_1, val * 4); -+ } - 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) { -- if (video->srcs[0].size) -- aspeed_video_free_buf(video, &video->srcs[0]); -- if (video->srcs[1].size) -- aspeed_video_free_buf(video, &video->srcs[1]); -- -- if (!aspeed_video_alloc_buf(video, &video->srcs[0], size)) -- goto err_mem; -- if (!aspeed_video_alloc_buf(video, &video->srcs[1], size)) -- goto err_mem; -- -- v4l2_dbg(1, debug, &video->v4l2_dev, "src buf0 addr(%pad) size(%d)\n", -- &video->srcs[0].dma, video->srcs[0].size); -- v4l2_dbg(1, debug, &video->v4l2_dev, "src buf1 addr(%pad) size(%d)\n", -- &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); -- } -- -- 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)); ++ pci_stop_root_bus(pcie->host->bus); ++ pci_remove_root_bus(pcie->host->bus); ++ aspeed_pcie_irq_domain_free(pcie); +} - --err_mem: -- dev_err(video->dev, "Failed to allocate source buffers\n"); -+/* -+ * Update relative parameters when timing changed. -+ * -+ * @video: the struct of aspeed_video -+ * @timings: the new timings -+ */ -+static void aspeed_video_update_timings(struct aspeed_video *video, struct v4l2_bt_timings *timings) -+{ -+ video->active_timings = *timings; -+ aspeed_video_set_resolution(video); - -- if (video->srcs[0].size) -- aspeed_video_free_buf(video, &video->srcs[0]); -+ video->pix_fmt.width = timings->width; -+ video->pix_fmt.height = timings->height; -+ video->pix_fmt.sizeimage = video->max_compressed_size; - } - - static void aspeed_video_update_regs(struct aspeed_video *video) -@@ -1219,6 +1720,8 @@ - u32 ctrl = 0; - u32 seq_ctrl = 0; - -+ v4l2_dbg(1, debug, &video->v4l2_dev, "input(%s)\n", -+ input_str[video->input]); - 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 +1737,26 @@ - else - aspeed_video_update(video, VE_BCD_CTRL, VE_BCD_CTRL_EN_BCD, 0); - -+ if (video->input == VIDEO_INPUT_VGA) -+ ctrl |= VE_CTRL_AUTO_OR_CURSOR; + -+ if (video->input == VIDEO_INPUT_DVI) -+ ctrl |= VE_CTRL_SOURCE; ++static struct aspeed_pcie_rc_platform pcie_rc_ast2600 = { ++ .setup = aspeed_ast2600_setup, ++ .reg_intx_en = 0x04, ++ .reg_intx_sts = 0x08, ++ .reg_msi_en = 0x20, ++ .reg_msi_sts = 0x28, ++ .msi_address = 0x1e77005c, ++}; + - if (video->frame_rate) - ctrl |= FIELD_PREP(VE_CTRL_FRC, video->frame_rate); - -+ if (video->format == VIDEO_FMT_PARTIAL) -+ ctrl |= video->compare_only; ++static struct aspeed_pcie_rc_platform pcie_rc_ast2700 = { ++ .setup = aspeed_ast2700_setup, ++ .reg_intx_en = 0x40, ++ .reg_intx_sts = 0x48, ++ .reg_msi_en = 0x50, ++ .reg_msi_sts = 0x58, ++ .msi_address = 0x000000f0, ++}; + - if (video->format == VIDEO_FMT_STANDARD) { - comp_ctrl &= ~FIELD_PREP(VE_COMP_CTRL_EN_HQ, video->hq_mode); - seq_ctrl |= video->jpeg_mode; - } - -+ if (video->format != VIDEO_FMT_PARTIAL) -+ seq_ctrl |= VE_SEQ_CTRL_AUTO_COMP; ++static const struct of_device_id aspeed_pcie_of_match[] = { ++ { .compatible = "aspeed,ast2600-pcie", .data = &pcie_rc_ast2600 }, ++ { .compatible = "aspeed,ast2700-pcie", .data = &pcie_rc_ast2700 }, ++ {} ++}; + - if (video->yuv420) - seq_ctrl |= VE_SEQ_CTRL_YUV420; - -@@ -1252,7 +1767,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); - 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 +1795,16 @@ - aspeed_video_write(video, VE_COMP_OFFSET, 0); - - aspeed_video_write(video, VE_JPEG_ADDR, video->jpeg.dma); -+ aspeed_video_write(video, VE_BCD_ADDR, _make_addr(video->bcd.dma)); - - /* Set control registers */ -+ aspeed_video_write(video, VE_SEQ_CTRL, VE_SEQ_CTRL_AUTO_COMP); -+ if (video->version == 7) { -+ if (video->input == VIDEO_INPUT_DVI) -+ ctrl |= FIELD_PREP(VE_CTRL_CLK_DELAY, VIDEO_CLK_CRT2); -+ 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 +1836,7 @@ - aspeed_video_get_resolution(video); - - /* Set timings since the device is being opened for the first time */ -- video->active_timings = video->detected_timings; -- aspeed_video_set_resolution(video); -- -- video->pix_fmt.width = video->active_timings.width; -- video->pix_fmt.height = video->active_timings.height; -- video->pix_fmt.sizeimage = video->max_compressed_size; -+ aspeed_video_update_timings(video, &video->detected_timings); - } - - static void aspeed_video_stop(struct aspeed_video *video) -@@ -1326,15 +1846,6 @@ - - aspeed_video_off(video); - -- if (video->srcs[0].size) -- aspeed_video_free_buf(video, &video->srcs[0]); -- -- if (video->srcs[1].size) -- aspeed_video_free_buf(video, &video->srcs[1]); -- -- if (video->bcd.size) -- aspeed_video_free_buf(video, &video->bcd); -- - video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; - video->flags = 0; - } -@@ -1342,10 +1853,14 @@ - static int aspeed_video_querycap(struct file *file, void *fh, - struct v4l2_capability *cap) - { -+ struct aspeed_video *video = video_drvdata(file); ++static struct platform_driver aspeed_pcie_driver = { ++ .driver = { ++ .name = "aspeed-pcie", ++ .suppress_bind_attrs = true, ++ .of_match_table = aspeed_pcie_of_match, ++ }, ++ .probe = aspeed_pcie_probe, ++ .remove_new = aspeed_pcie_remove, ++}; + - strscpy(cap->driver, DEVICE_NAME, sizeof(cap->driver)); - strscpy(cap->card, "Aspeed Video Engine", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - DEVICE_NAME); -+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform: %s%d", -+ DEVICE_NAME, video->id); - - return 0; - } -@@ -1383,7 +1898,8 @@ - - switch (f->fmt.pix.pixelformat) { - case V4L2_PIX_FMT_JPEG: -- video->format = VIDEO_FMT_STANDARD; -+ video->format = (f->fmt.pix.flags == V4L2_PIX_FMT_FLAG_PARTIAL_JPG) -+ ? VIDEO_FMT_PARTIAL : VIDEO_FMT_STANDARD; - break; - case V4L2_PIX_FMT_AJPG: - video->format = VIDEO_FMT_ASPEED; -@@ -1401,10 +1917,10 @@ - { - struct aspeed_video *video = video_drvdata(file); - -- if (inp->index) -+ if (inp->index >= VIDEO_INPUT_MAX) - return -EINVAL; - -- strscpy(inp->name, "Host VGA capture", sizeof(inp->name)); -+ sprintf(inp->name, "%s capture", input_str[inp->index]); - inp->type = V4L2_INPUT_TYPE_CAMERA; - inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; - inp->status = video->v4l2_input_status; -@@ -1414,16 +1930,111 @@ ++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 @@ - static int aspeed_video_get_input(struct file *file, void *fh, unsigned int *i) - { -- *i = 0; -+ struct aspeed_video *video = video_drvdata(file); + 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 @@ ++# SPDX-License-Identifier: GPL-2.0-only + -+ *i = video->input; - - return 0; - } - - static int aspeed_video_set_input(struct file *file, void *fh, unsigned int i) - { -- if (i) -+ struct aspeed_video *video = video_drvdata(file); ++# ++# PHY drivers for ASPEED ++# + -+ if (i >= VIDEO_INPUT_MAX) - return -EINVAL; - -+ if (IS_ERR(video->scu)) { -+ v4l2_dbg(1, debug, &video->v4l2_dev, "%s: scu isn't ready for input-control\n", __func__); -+ return -EINVAL; -+ } ++config PHY_ASPEED_SGMII ++ tristate "ASPEED SGMII PHY driver" ++ select REGMAP ++ select MFD_SYSCON ++ select GENERIC_PHY ++ depends on ARCH_ASPEED ++ default n ++ help ++ Enable driver support for Aspeed AST2700 PHY SGMII. + -+ 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; -+ } ++config PHY_ASPEED_USB3 ++ tristate "ASPEED USB3 PHY driver" ++ select GENERIC_PHY ++ depends on ARCH_ASPEED ++ default n ++ help ++ Enable driver support for Aspeed AST2700 PHY USB3. +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 +@@ -0,0 +1,4 @@ ++# SPDX-License-Identifier: GPL-2.0 + -+ // prepare memory space for user to put test batch -+ if (i == VIDEO_INPUT_MEM && !video->dbg_src.size) { -+ if (!aspeed_video_alloc_buf(video, &video->dbg_src, VE_MAX_SRC_BUFFER_SIZE)) { -+ v4l2_err(&video->v4l2_dev, "Failed to allocate buffer for debug input\n"); -+ return -EINVAL; -+ } -+ v4l2_dbg(1, debug, &video->v4l2_dev, "dbg src addr(%pad) size(%d)\n", -+ &video->dbg_src.dma, video->dbg_src.size); -+ } -+ if (i != VIDEO_INPUT_MEM && video->dbg_src.size) -+ aspeed_video_free_buf(video, &video->dbg_src); ++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 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright 2023 Aspeed Technology Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ if (i == VIDEO_INPUT_DVI && video->version == 7) { -+ if (IS_ERR(video->dvi_base)) { -+ v4l2_err(&video->v4l2_dev, "%s: dvi isn't ready for DVI input\n", __func__); -+ return -EINVAL; -+ } ++#define SGMII_CFG 0x00 ++#define SGMII_LINK_TIMER 0x08 ++#define SGMII_NWAY_ACK 0x0c ++#define SGMII_PHY_CFG1 0x18 ++#define SGMII_PHY_PIPE_CTL 0x20 ++#define SGMII_FIFO_DELAY_THREHOLD 0x28 ++#define SGMII_MODE 0x30 + -+ /* Set DVI mode detection defaults */ -+ writel(FIELD_PREP(VE_MODE_DT_HOR_TOLER, 2) | -+ FIELD_PREP(VE_MODE_DT_VER_TOLER, 2) | -+ FIELD_PREP(VE_MODE_DT_HOR_STABLE, 6) | -+ FIELD_PREP(VE_MODE_DT_VER_STABLE, 6) | -+ FIELD_PREP(VE_MODE_DT_EDG_THROD, 0x65), -+ video->dvi_base + VE_MODE_DETECT); -+ } ++#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) + -+ video->input = i; ++#define PLDA_CLK 0x268 + -+ if (video->version == 6) { -+ /* modify dpll source per current input */ -+ if (video->input == VIDEO_INPUT_VGA) -+ regmap_update_bits(video->scu, SCU_MISC_CTRL, SCU_DPLL_SOURCE, 0); -+ else -+ regmap_update_bits(video->scu, SCU_MISC_CTRL, SCU_DPLL_SOURCE, SCU_DPLL_SOURCE); ++#define PLDA_CLK_SEL_INTERNAL_25M BIT(8) ++#define PLDA_CLK_FREQ_MULTI GENMASK(7, 0) + -+ // SLI direction: inverse if DVI -+ if (video->input == VIDEO_INPUT_DVI) { -+ regmap_update_bits(video->scu, SCU_MULTI_FUNC_12, -+ SCU_MULTI_FUNC_CPU_SLI_DIR, -+ SCU_MULTI_FUNC_CPU_SLI_DIR); -+ regmap_update_bits(video->scu, SCU_MULTI_FUNC_15, -+ SCU_MULTI_FUNC_IO_SLI_DIR, -+ SCU_MULTI_FUNC_IO_SLI_DIR); -+ regmap_update_bits(video->scu, SCU_CLK_SEL2, -+ SCU_VIDEO_OUTPUT_DELAY, -+ 4); -+ } else { -+ regmap_update_bits(video->scu, SCU_MULTI_FUNC_12, -+ SCU_MULTI_FUNC_CPU_SLI_DIR, -+ 0); -+ regmap_update_bits(video->scu, SCU_MULTI_FUNC_15, -+ SCU_MULTI_FUNC_IO_SLI_DIR, -+ 0); -+ } -+ } else if (video->version == 7) { -+ if (video->input == VIDEO_INPUT_DVI) { -+ // CRT2CLK = 500 * R / N -+ regmap_write(video->scu, SCU_CRT2CLK, -+ FIELD_PREP(SCU_CRT2CLK_N, 50) | FIELD_PREP(SCU_CRT2CLK_R, 15)); ++struct aspeed_sgmii { ++ struct device *dev; ++ void __iomem *regs; ++ struct regmap *plda_regmap; ++}; + -+ regmap_write(video->scu, SCU_CLK_SEL, FIELD_PREP(SCU_SOC_DISPLAY_SEL, 1)); -+ } else { -+ regmap_write(video->scu, SCU_CLK_SEL, FIELD_PREP(SCU_SOC_DISPLAY_SEL, 0)); -+ } -+ } ++static void aspeed_sgmii_set_nway(struct phy *phy) ++{ ++ struct aspeed_sgmii *sgmii = phy_get_drvdata(phy); ++ u32 reg; + -+ aspeed_video_update_regs(video); ++ /* ++ * 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); + -+ // update signal status -+ if (video->input == VIDEO_INPUT_MEM) { -+ video->v4l2_input_status = 0; -+ } else { -+ aspeed_video_get_resolution(video); -+ if (!video->v4l2_input_status) -+ aspeed_video_update_timings(video, &video->detected_timings); -+ } ++ writel(0, sgmii->regs + SGMII_MODE); + -+ if (video->input == VIDEO_INPUT_MEM) -+ aspeed_video_start_frame(video); ++ writel(0, sgmii->regs + SGMII_CFG); ++ reg = SGMII_CFG_SW_RESET | SGMII_CFG_PWR_DOWN; ++ writel(reg, sgmii->regs + SGMII_CFG); + - return 0; - } - -@@ -1520,6 +2131,12 @@ - { - struct aspeed_video *video = video_drvdata(file); - -+ // if input is MEM, resolution decided by user -+ if (video->input == VIDEO_INPUT_MEM) { -+ video->detected_timings.width = timings->bt.width; -+ video->detected_timings.height = timings->bt.height; -+ } ++ reg = SGMII_CFG_AN_ENABLE; ++ writel(reg, sgmii->regs + SGMII_CFG); + - if (timings->bt.width == video->active_timings.width && - timings->bt.height == video->active_timings.height) - return 0; -@@ -1527,13 +2144,7 @@ - if (vb2_is_busy(&video->queue)) - return -EBUSY; - -- video->active_timings = timings->bt; -- -- aspeed_video_set_resolution(video); -- -- video->pix_fmt.width = timings->bt.width; -- video->pix_fmt.height = timings->bt.height; -- video->pix_fmt.sizeimage = video->max_compressed_size; -+ aspeed_video_update_timings(video, &timings->bt); - - timings->type = V4L2_DV_BT_656_1120; - -@@ -1589,6 +2200,37 @@ - NULL, NULL); - } - -+static int aspeed_video_g_selection(struct file *file, void *fh, -+ struct v4l2_selection *s) -+{ -+ struct aspeed_video *video = video_drvdata(file); -+ struct aspeed_video_box *box; -+ unsigned long flags; ++ writel(0x0c, sgmii->regs + SGMII_FIFO_DELAY_THREHOLD); + -+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && -+ s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) -+ return -EINVAL; ++ writel(SGMII_PCTL_TX_NO_DEEMPH, sgmii->regs + SGMII_PHY_PIPE_CTL); + -+ switch (s->target) { -+ case V4L2_SEL_TGT_CROP_DEFAULT: -+ spin_lock_irqsave(&video->lock, flags); -+ box = list_first_entry_or_null(&video->boxes, -+ struct aspeed_video_box, -+ link); -+ if (box) { -+ s->r = box->box; -+ list_del(&box->link); -+ kfree(box); -+ } else { -+ memset(&s->r, 0, sizeof(s->r)); -+ } -+ spin_unlock_irqrestore(&video->lock, flags); -+ return 0; -+ } ++ /* Set link timer for Nway state change */ ++ writel(0x100, sgmii->regs + SGMII_LINK_TIMER); + -+ return -EINVAL; ++ /* 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); +} + - static int aspeed_video_dv_timings_cap(struct file *file, void *fh, - struct v4l2_dv_timings_cap *cap) - { -@@ -1641,6 +2283,8 @@ - .vidioc_enum_dv_timings = aspeed_video_enum_dv_timings, - .vidioc_dv_timings_cap = aspeed_video_dv_timings_cap, - -+ .vidioc_g_selection = aspeed_video_g_selection, ++static int aspeed_sgmii_phy_init(struct phy *phy) ++{ ++ aspeed_sgmii_set_nway(phy); + - .vidioc_subscribe_event = aspeed_video_sub_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, - }; -@@ -1710,6 +2354,9 @@ - struct delayed_work *dwork = to_delayed_work(work); - struct aspeed_video *video = container_of(dwork, struct aspeed_video, - res_work); -+ bool is_res_chg = false; ++ return 0; ++} + -+ aspeed_video_reset(video); - - aspeed_video_on(video); - -@@ -1723,8 +2370,14 @@ - - aspeed_video_get_resolution(video); - -- if (video->detected_timings.width != video->active_timings.width || -- video->detected_timings.height != video->active_timings.height) { -+ if (video->v4l2_input_status) -+ goto done; ++static int aspeed_sgmii_phy_exit(struct phy *phy) ++{ ++ struct aspeed_sgmii *sgmii = phy_get_drvdata(phy); + -+ is_res_chg = (video->detected_timings.width != video->active_timings.width || -+ video->detected_timings.height != video->active_timings.height); -+ aspeed_video_update_timings(video, &video->detected_timings); ++ /* Disable SGMII controller */ ++ writel(0, sgmii->regs + SGMII_MODE); + -+ if (is_res_chg) { - static const struct v4l2_event ev = { - .type = V4L2_EVENT_SOURCE_CHANGE, - .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, -@@ -1740,6 +2393,32 @@ - done: - clear_bit(VIDEO_RES_CHANGE, &video->flags); - wake_up_interruptible_all(&video->wait); -+ wake_up_all(&waitq); ++ return 0; +} + -+/* -+ * To mmap source memory for test from memory usage. -+ * test from memory input mode requires much bigger size because it is -+ * uncompressed BGRA format. Thus, We use VM_READ to tell it is for test -+ * or v4l2 now. -+ */ -+static int aspeed_video_mmap(struct file *file, struct vm_area_struct *vma) ++static int aspeed_sgmii_phy_set_speed(struct phy *phy, int speed) +{ -+ int rc; -+ struct aspeed_video *v = video_drvdata(file); -+ const size_t size = vma->vm_end - vma->vm_start; -+ const unsigned long pfn = __phys_to_pfn(v->dbg_src.dma); ++ struct aspeed_sgmii *sgmii = phy_get_drvdata(phy); ++ u32 reg; + -+ if (v->input != VIDEO_INPUT_MEM || vma->vm_flags & VM_READ) -+ return vb2_fop_mmap(file, vma); ++ reg = PLDA_CLK_SEL_INTERNAL_25M | FIELD_PREP(PLDA_CLK_FREQ_MULTI, 0x2b); ++ regmap_write(sgmii->plda_regmap, PLDA_CLK, reg); + -+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); -+ rc = remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot); -+ if (rc) { -+ v4l2_err(&v->v4l2_dev, "remap_pfn_range failed(%d)\n", rc); -+ return -EAGAIN; ++ 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; + } -+ return 0; - } - - static int aspeed_video_open(struct file *file) -@@ -1785,7 +2464,7 @@ - .read = vb2_fop_read, - .poll = vb2_fop_poll, - .unlocked_ioctl = video_ioctl2, -- .mmap = vb2_fop_mmap, -+ .mmap = aspeed_video_mmap, - .open = aspeed_video_open, - .release = aspeed_video_release, - }; -@@ -1827,16 +2506,22 @@ - 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; -+ set_bit(VIDEO_BOUNDING_BOX, &video->flags); - - aspeed_video_update_regs(video); - -- rc = aspeed_video_start_frame(video); -- if (rc) { -- aspeed_video_bufs_done(video, VB2_BUF_STATE_QUEUED); -- return rc; -+ // if input is MEM, don't start capture until user acquire -+ if (video->input != VIDEO_INPUT_MEM) { -+ rc = aspeed_video_start_frame(video); -+ if (rc) { -+ aspeed_video_bufs_done(video, VB2_BUF_STATE_QUEUED); -+ return rc; -+ } - } - - set_bit(VIDEO_STREAMING, &video->flags); -@@ -1848,6 +2533,8 @@ - int rc; - struct aspeed_video *video = vb2_get_drv_priv(q); - -+ aspeed_video_set_vga_on(video, false); ++ writel(0, sgmii->regs + SGMII_MODE); + - clear_bit(VIDEO_STREAMING, &video->flags); - - rc = wait_event_timeout(video->wait, -@@ -1860,8 +2547,7 @@ - * Need to force stop any DMA and try and get HW into a good - * state for future calls to start streaming again. - */ -- aspeed_video_off(video); -- aspeed_video_on(video); -+ aspeed_video_reset(video); - - aspeed_video_init_regs(video); - -@@ -1885,7 +2571,8 @@ - spin_unlock_irqrestore(&video->lock, flags); - - if (test_bit(VIDEO_STREAMING, &video->flags) && -- !test_bit(VIDEO_FRAME_INPRG, &video->flags) && empty) -+ !test_bit(VIDEO_FRAME_INPRG, &video->flags) && empty && -+ (video->input != VIDEO_INPUT_MEM)) - aspeed_video_start_frame(video); - } - -@@ -1911,6 +2598,7 @@ - val08 = aspeed_video_read(v, VE_CTRL); - if (FIELD_GET(VE_CTRL_DIRECT_FETCH, val08)) { - seq_printf(s, " %-20s:\tDirect fetch\n", "Mode"); -+ seq_printf(s, " %-20s:\t%s\n", "Input", input_str[v->input]); - seq_printf(s, " %-20s:\t%s\n", "VGA bpp mode", - FIELD_GET(VE_CTRL_INT_DE, val08) ? "16" : "32"); - } else { -@@ -1962,19 +2650,19 @@ - } - DEFINE_SHOW_ATTRIBUTE(aspeed_video_debugfs); - --static struct dentry *debugfs_entry; -- - static void aspeed_video_debugfs_remove(struct aspeed_video *video) - { -- debugfs_remove_recursive(debugfs_entry); -- debugfs_entry = NULL; -+ debugfs_remove_recursive(video->debugfs_entry); - } - - static void aspeed_video_debugfs_create(struct aspeed_video *video) - { -- debugfs_entry = debugfs_create_file(DEVICE_NAME, 0444, NULL, -- video, -- &aspeed_video_debugfs_fops); -+ char filename[16]; ++ writel((reg >> 2), sgmii->regs + SGMII_PHY_CFG1); + -+ snprintf(filename, sizeof(filename), "%s%d", DEVICE_NAME, video->id); -+ video->debugfs_entry = debugfs_create_file(filename, 0444, -+ video->debugfs_entry, video, -+ &aspeed_video_debugfs_fops); - } - #else - static void aspeed_video_debugfs_remove(struct aspeed_video *video) { } -@@ -2028,6 +2716,8 @@ - vbq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - vbq->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF; - vbq->dev = v4l2_dev->dev; -+ snprintf(vdev->name, sizeof(vdev->name), "%s%d", -+ DEVICE_NAME, video->id); - vbq->lock = &video->video_lock; - vbq->ops = &aspeed_video_vb2_ops; - vbq->mem_ops = &vb2_dma_contig_memops; -@@ -2070,11 +2760,30 @@ - return 0; - } - -+/* -+ * Get regmap without checking res, such as clk/reset, that could lead to -+ * conflict. -+ */ -+static struct regmap *aspeed_regmap_lookup(struct device_node *np, const char *property) -+{ -+ struct device_node *syscon_np __free(device_node) = of_parse_phandle(np, property, 0); ++ 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); + -+ if (!syscon_np) -+ return ERR_PTR(-ENODEV); ++ writel(0x0c, sgmii->regs + SGMII_FIFO_DELAY_THREHOLD); ++ writel(SGMII_PCTL_TX_NO_DEEMPH, sgmii->regs + SGMII_PHY_PIPE_CTL); + -+ return device_node_to_regmap(syscon_np); ++ /* 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 int aspeed_video_init(struct aspeed_video *video) - { - int irq; - int rc; - struct device *dev = video->dev; -+ unsigned int mask_size = (video->version >= 7) ? 64 : 32; -+ u32 resv_size = VE_MAX_SRC_BUFFER_SIZE * 2 + VE_JPEG_HEADER_SIZE + VE_BCD_BUFF_SIZE; ++static const struct phy_ops aspeed_sgmii_phyops = { ++ .init = aspeed_sgmii_phy_init, ++ .set_speed = aspeed_sgmii_phy_set_speed, ++ .exit = aspeed_sgmii_phy_exit, ++ .owner = THIS_MODULE, ++}; + -+ video->scu = aspeed_regmap_lookup(dev->of_node, "aspeed,scu"); -+ video->gfx = aspeed_regmap_lookup(dev->of_node, "aspeed,gfx"); - - irq = irq_of_parse_and_map(dev->of_node, 0); - if (!irq) { -@@ -2082,14 +2791,36 @@ - return -ENODEV; - } - -- rc = devm_request_threaded_irq(dev, irq, NULL, aspeed_video_irq, -- IRQF_ONESHOT, DEVICE_NAME, video); -+ rc = devm_request_threaded_irq(dev, irq, aspeed_video_irq, -+ aspeed_video_thread_irq, -+ IRQF_ONESHOT, dev_name(dev), video); - if (rc < 0) { - dev_err(dev, "Unable to request IRQ %d\n", irq); - return rc; - } - dev_info(video->dev, "irq %d\n", irq); - -+ if (!IS_ERR(video->dvi_base)) { -+ irq = irq_of_parse_and_map(dev->of_node, 1); -+ if (!irq) { -+ dev_err(dev, "Unable to find DVI IRQ\n"); -+ return -ENODEV; -+ } ++static int aspeed_sgmii_probe(struct platform_device *pdev) ++{ ++ struct aspeed_sgmii *sgmii; ++ struct resource *res; ++ struct device *dev; ++ struct device_node *np; ++ struct phy_provider *provider; ++ struct phy *phy; + -+ rc = devm_request_irq(dev, irq, aspeed_video_md_irq, 0, dev_name(dev), video); -+ if (rc < 0) { -+ dev_err(dev, "Unable to request DVI IRQ %d\n", irq); -+ return rc; -+ } -+ dev_info(video->dev, "dvi mode-detection irq %d\n", irq); ++ dev = &pdev->dev; ++ ++ sgmii = devm_kzalloc(dev, sizeof(*sgmii), GFP_KERNEL); ++ if (!sgmii) ++ return -ENOMEM; ++ ++ sgmii->dev = dev; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(dev, "cannot get resource\n"); ++ return -ENODEV; + } + -+ video->reset = devm_reset_control_get_shared(dev, NULL); -+ if (IS_ERR(video->reset)) { -+ dev_err(dev, "Unable to get reset\n"); -+ return PTR_ERR(video->reset); ++ sgmii->regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR(sgmii->regs)) { ++ dev_err(dev, "cannot map registers\n"); ++ return PTR_ERR(sgmii->regs); + } + - video->eclk = devm_clk_get(dev, "eclk"); - if (IS_ERR(video->eclk)) { - dev_err(dev, "Unable to get ECLK\n"); -@@ -2111,22 +2842,53 @@ - if (rc) - goto err_unprepare_eclk; - -+ if (video->version > 6) { -+ video->crt2clk = devm_clk_get(dev, "crt2clk"); -+ if (IS_ERR(video->crt2clk)) { -+ dev_err(dev, "Unable to get CRT2CLK\n"); -+ rc = PTR_ERR(video->crt2clk); -+ goto err_unprepare_vclk; -+ } ++ 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); ++ } + -+ rc = clk_prepare_enable(video->crt2clk); -+ if (rc) -+ goto err_unprepare_vclk; ++ phy = devm_phy_create(dev, NULL, &aspeed_sgmii_phyops); ++ if (IS_ERR(phy)) { ++ dev_err(&pdev->dev, "failed to create PHY\n"); ++ return PTR_ERR(phy); + } + - of_reserved_mem_device_init(dev); - -- rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); -+ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(mask_size)); - if (rc) { - dev_err(dev, "Failed to set DMA mask\n"); - goto err_release_reserved_mem; - } - -- if (!aspeed_video_alloc_buf(video, &video->jpeg, -- VE_JPEG_HEADER_SIZE)) { -- dev_err(dev, "Failed to allocate DMA for JPEG header\n"); -+ if (!aspeed_video_alloc_buf(video, &video->pool, resv_size)) { -+ dev_err(dev, "Failed to allocate DMA pool\n"); - rc = -ENOMEM; - goto err_release_reserved_mem; - } -- dev_info(video->dev, "alloc mem size(%d) at %pad for jpeg header\n", -- VE_JPEG_HEADER_SIZE, &video->jpeg.dma); -+ video->jpeg.size = VE_JPEG_HEADER_SIZE; -+ video->jpeg.virt = video->pool.virt; -+ video->jpeg.dma = video->pool.dma; -+ video->bcd.size = VE_BCD_BUFF_SIZE; -+ video->bcd.virt = video->jpeg.virt + video->jpeg.size; -+ video->bcd.dma = video->jpeg.dma + video->jpeg.size; -+ video->srcs[0].size = VE_MAX_SRC_BUFFER_SIZE; -+ video->srcs[0].dma = video->bcd.dma + video->bcd.size; -+ video->srcs[1].size = VE_MAX_SRC_BUFFER_SIZE; -+ video->srcs[1].dma = video->srcs[0].dma + video->srcs[0].size; ++ provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); ++ if (IS_ERR(provider)) ++ return PTR_ERR(provider); + -+ dev_info(video->dev, "alloc mem size(%d) at %pad for pool\n", -+ resv_size, &video->pool.dma); -+ v4l2_dbg(1, debug, &video->v4l2_dev, "jpeg header addr(%pad) size(%d)\n", -+ &video->jpeg.dma, video->jpeg.size); -+ v4l2_dbg(1, debug, &video->v4l2_dev, "bcd addr(%pad) size(%d)\n", -+ &video->bcd.dma, video->bcd.size); -+ v4l2_dbg(1, debug, &video->v4l2_dev, "src buf0 addr(%pad) size(%d)\n", -+ &video->srcs[0].dma, video->srcs[0].size); -+ v4l2_dbg(1, debug, &video->v4l2_dev, "src buf1 addr(%pad) size(%d)\n", -+ &video->srcs[1].dma, video->srcs[1].size); - - aspeed_video_init_jpeg_table(video->jpeg.virt, video->yuv420); - -@@ -2134,6 +2896,9 @@ - - err_release_reserved_mem: - of_reserved_mem_device_release(dev); -+ if (!IS_ERR(video->crt2clk)) -+ clk_disable_unprepare(video->crt2clk); -+err_unprepare_vclk: - clk_unprepare(video->vclk); - err_unprepare_eclk: - clk_unprepare(video->eclk); -@@ -2145,6 +2910,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 }, -+ { .compatible = "aspeed,ast2700-video-engine", .data = &ast2700_config }, - {} - }; - MODULE_DEVICE_TABLE(of, aspeed_video_of_match); -@@ -2154,11 +2920,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; - -+ video->id = of_alias_get_id(pdev->dev.of_node, "video"); -+ if (video->id < 0) -+ video->id = 0; ++ phy_set_drvdata(phy, sgmii); + - video->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(video->base)) - return PTR_ERR(video->base); -@@ -2167,8 +2938,10 @@ - if (!config) - return -ENODEV; - -+ video->version = config->version; - video->jpeg_mode = config->jpeg_mode; - video->comp_size_read = config->comp_size_read; -+ video->compare_only = config->compare_only; - - video->frame_rate = 30; - video->jpeg_hq_quality = 1; -@@ -2178,14 +2951,31 @@ - init_waitqueue_head(&video->wait); - INIT_DELAYED_WORK(&video->res_work, aspeed_video_resolution_work); - INIT_LIST_HEAD(&video->buffers); -+ INIT_LIST_HEAD(&video->boxes); ++ dev_info(dev, "module loaded\n"); + -+ video->rst_wq = create_singlethread_workqueue("video_rst_wq"); -+ if (!video->rst_wq) { -+ dev_err(&pdev->dev, "unable to alloc rst workqueue\n"); -+ return -ENOMEM; -+ } -+ INIT_WORK(&video->rst_work, aspeed_video_rst_worker); ++ return 0; ++} + -+ if (video->version == 7 && video->id == 0) -+ video->dvi_base = devm_platform_ioremap_resource(pdev, 1); -+ else -+ video->dvi_base = ERR_PTR(-ENODEV); - - rc = aspeed_video_init(video); - 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); ++static const struct of_device_id aspeed_sgmii_of_matches[] = { ++ { .compatible = "aspeed,ast2700-sgmii" }, ++ { }, ++}; + - 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 +2983,9 @@ - - aspeed_video_debugfs_create(video); - -+ dev_info(video->dev, "%s%d registered as /dev/video%d\n", DEVICE_NAME, -+ video->id, video->vdev.num); ++static struct platform_driver aspeed_sgmii_driver = { ++ .probe = aspeed_sgmii_probe, ++ .driver = { ++ .name = "aspeed-sgmii", ++ .of_match_table = aspeed_sgmii_of_matches, ++ }, ++}; + - return 0; - } - -@@ -2204,8 +2997,12 @@ - - aspeed_video_off(video); - -+ destroy_workqueue(video->rst_wq); ++module_platform_driver(aspeed_sgmii_driver); + - aspeed_video_debugfs_remove(video); - -+ if (!IS_ERR(video->crt2clk)) -+ clk_disable_unprepare(video->crt2clk); - clk_unprepare(video->vclk); - clk_unprepare(video->eclk); - -@@ -2215,7 +3012,7 @@ - - v4l2_device_unregister(v4l2_dev); - -- aspeed_video_free_buf(video, &video->jpeg); -+ aspeed_video_free_buf(video, &video->pool); - - 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 2026-04-08 18:03:47.802714601 +0000 -@@ -11,8 +11,10 @@ - #include - #include - #include -+#include - #include - #include ++MODULE_AUTHOR("Jacky Chou "); ++MODULE_DESCRIPTION("Control of ASPEED SGMII Device"); ++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 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright 2023 Aspeed Technology Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include +#include - #include - - #include "sdhci-pltfm.h" -@@ -23,6 +25,8 @@ - #define ASPEED_SDC_PHASE 0xf4 - #define ASPEED_SDC_S1_PHASE_IN GENMASK(25, 21) - #define ASPEED_SDC_S0_PHASE_IN GENMASK(20, 16) -+#define ASPEED_SDC_S0_PHASE_IN_SHIFT 16 -+#define ASPEED_SDC_S0_PHASE_OUT_SHIFT 3 - #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 @@ - #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 ++#include + - /* SDIO{10,20} */ --#define ASPEED_SDC_CAP1_1_8V (0 * 32 + 26) -+#define ASPEED_SDC_CAP1_1_8V (0 * 32 + 26) - /* SDIO{14,24} */ --#define ASPEED_SDC_CAP2_SDR104 (1 * 32 + 1) -+#define ASPEED_SDC_CAP2_SDR104 (1 * 32 + 1) ++#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 PROBE_AFTER_ASSET_DEASSERT 0x1 ++#define DWC_CRTL_NUM 3 + -+struct aspeed_sdc_info { -+ u32 flag; ++#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; ++ void __iomem *regs; ++ const struct aspeed_usb_phy3_model *model; ++ bool phy_ext_load_quirk; +}; - - struct aspeed_sdc { - struct clk *clk; - struct resource *res; -+ struct reset_control *rst; - - spinlock_t lock; - void __iomem *regs; - }; - --struct aspeed_sdhci_tap_param { -- bool valid; -- --#define ASPEED_SDHCI_TAP_PARAM_INVERT_CLK BIT(4) -- u8 in; -- u8 out; --}; -- --struct aspeed_sdhci_tap_desc { -- u32 tap_mask; -- u32 enable_mask; -- u8 enable_value; --}; -- --struct aspeed_sdhci_phase_desc { -- struct aspeed_sdhci_tap_desc in; -- struct aspeed_sdhci_tap_desc out; --}; -- - struct aspeed_sdhci_pdata { - unsigned int clk_div_start; -- const struct aspeed_sdhci_phase_desc *phase_desc; -- size_t nr_phase_descs; - }; - - struct aspeed_sdhci { - const struct aspeed_sdhci_pdata *pdata; - struct aspeed_sdc *parent; - u32 width_mask; -- struct mmc_clk_phase_map phase_map; -- const struct aspeed_sdhci_phase_desc *phase_desc; ++ ++struct usb_dwc3_ctrl { ++ u32 offset; ++ u32 value; +}; + -+static struct aspeed_sdc_info ast2600_sdc_info = { -+ .flag = PROBE_AFTER_ASSET_DEASSERT - }; - - /* - * The function sets the mirror register for updating - * capbilities of the current slot. - * -- * slot | capability | caps_reg | mirror_reg -+ * slot | capability | caps_reg | mirror_reg - * -----|-------------|----------|------------ -- * 0 | CAP1_1_8V | SDIO140 | SDIO10 -+ * 0 | CAP1_1_8V | SDIO140 | SDIO10 - * 0 | CAP2_SDR104 | SDIO144 | SDIO14 -- * 1 | CAP1_1_8V | SDIO240 | SDIO20 -+ * 1 | CAP1_1_8V | SDIO240 | SDIO20 - * 1 | CAP2_SDR104 | SDIO244 | SDIO24 - */ - static void aspeed_sdc_set_slot_capability(struct sdhci_host *host, struct aspeed_sdc *sdc, -@@ -125,222 +120,217 @@ - spin_unlock(&sdc->lock); - } - --static u32 --aspeed_sdc_set_phase_tap(const struct aspeed_sdhci_tap_desc *desc, -- u8 tap, bool enable, u32 reg) --{ -- reg &= ~(desc->enable_mask | desc->tap_mask); -- if (enable) { -- reg |= tap << __ffs(desc->tap_mask); -- reg |= desc->enable_value << __ffs(desc->enable_mask); -- } -- -- return reg; --} -- --static void --aspeed_sdc_set_phase_taps(struct aspeed_sdc *sdc, -- const struct aspeed_sdhci_phase_desc *desc, -- const struct aspeed_sdhci_tap_param *taps) -+static void aspeed_sdhci_set_bus_width(struct sdhci_host *host, int width) - { -- u32 reg; -+ struct sdhci_pltfm_host *pltfm_priv; -+ struct aspeed_sdhci *aspeed_sdhci; -+ struct aspeed_sdc *aspeed_sdc; -+ u8 ctrl; - -- spin_lock(&sdc->lock); -- reg = readl(sdc->regs + ASPEED_SDC_PHASE); -+ pltfm_priv = sdhci_priv(host); -+ aspeed_sdhci = sdhci_pltfm_priv(pltfm_priv); -+ aspeed_sdc = aspeed_sdhci->parent; - -- reg = aspeed_sdc_set_phase_tap(&desc->in, taps->in, taps->valid, reg); -- reg = aspeed_sdc_set_phase_tap(&desc->out, taps->out, taps->valid, reg); -+ /* Set/clear 8-bit mode */ -+ aspeed_sdc_configure_8bit_mode(aspeed_sdc, aspeed_sdhci, -+ width == MMC_BUS_WIDTH_8); - -- writel(reg, sdc->regs + ASPEED_SDC_PHASE); -- spin_unlock(&sdc->lock); -+ /* Set/clear 1 or 4 bit mode */ -+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); -+ if (width == MMC_BUS_WIDTH_4) -+ ctrl |= SDHCI_CTRL_4BITBUS; -+ else -+ ctrl &= ~SDHCI_CTRL_4BITBUS; -+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); - } - --#define PICOSECONDS_PER_SECOND 1000000000000ULL --#define ASPEED_SDHCI_NR_TAPS 15 --/* Measured value with *handwave* environmentals and static loading */ --#define ASPEED_SDHCI_MAX_TAP_DELAY_PS 1253 --static int aspeed_sdhci_phase_to_tap(struct device *dev, unsigned long rate_hz, -- int phase_deg) --{ -- u64 phase_period_ps; -- u64 prop_delay_ps; -- u64 clk_period_ps; -- unsigned int tap; -- u8 inverted; -- -- phase_deg %= 360; -- -- if (phase_deg >= 180) { -- inverted = ASPEED_SDHCI_TAP_PARAM_INVERT_CLK; -- phase_deg -= 180; -- dev_dbg(dev, -- "Inverting clock to reduce phase correction from %d to %d degrees\n", -- phase_deg + 180, phase_deg); -- } else { -- inverted = 0; -- } -+static u32 aspeed_sdhci_readl(struct sdhci_host *host, int reg) -+{ -+ u32 val = readl(host->ioaddr + reg); - -- prop_delay_ps = ASPEED_SDHCI_MAX_TAP_DELAY_PS / ASPEED_SDHCI_NR_TAPS; -- clk_period_ps = div_u64(PICOSECONDS_PER_SECOND, (u64)rate_hz); -- phase_period_ps = div_u64((u64)phase_deg * clk_period_ps, 360ULL); -- -- tap = div_u64(phase_period_ps, prop_delay_ps); -- if (tap > ASPEED_SDHCI_NR_TAPS) { -- dev_dbg(dev, -- "Requested out of range phase tap %d for %d degrees of phase compensation at %luHz, clamping to tap %d\n", -- tap, phase_deg, rate_hz, ASPEED_SDHCI_NR_TAPS); -- tap = ASPEED_SDHCI_NR_TAPS; -- } -+ if (unlikely(reg == SDHCI_PRESENT_STATE) && -+ (host->mmc->caps2 & MMC_CAP2_CD_ACTIVE_HIGH)) -+ val ^= SDHCI_CARD_PRESENT; - -- return inverted | tap; -+ return val; - } - --static void --aspeed_sdhci_phases_to_taps(struct device *dev, unsigned long rate, -- const struct mmc_clk_phase *phases, -- struct aspeed_sdhci_tap_param *taps) -+static void aspeed_sdhci_reset(struct sdhci_host *host, u8 mask) - { -- taps->valid = phases->valid; -+ struct sdhci_pltfm_host *pltfm_priv; -+ struct aspeed_sdhci *aspeed_sdhci; -+ struct aspeed_sdc *aspeed_sdc; -+ u32 save_array[8]; -+ u32 reg_array[] = {SDHCI_DMA_ADDRESS, -+ SDHCI_BLOCK_SIZE, -+ SDHCI_ARGUMENT, -+ SDHCI_HOST_CONTROL, -+ SDHCI_CLOCK_CONTROL, -+ SDHCI_INT_ENABLE, -+ SDHCI_SIGNAL_ENABLE, -+ SDHCI_AUTO_CMD_STATUS}; -+ int i; -+ u16 tran_mode; -+ u32 mmc8_mode; - -- if (!phases->valid) -- return; -+ 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]); - --static void --aspeed_sdhci_configure_phase(struct sdhci_host *host, unsigned long rate) --{ -- 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); - -- 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); - -- if (!sdhci->phase_desc) -- return; -+ for (i = 0; i < ARRAY_SIZE(reg_array); i++) -+ sdhci_writel(host, save_array[i], reg_array[i]); ++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 */ ++}; + -+ sdhci_writew(host, tran_mode, SDHCI_TRANSFER_MODE); -+ writel(mmc8_mode, aspeed_sdc->regs); - -- params = &sdhci->phase_map.phase[host->timing]; -- aspeed_sdhci_phases_to_taps(dev, rate, params, taps); -- aspeed_sdc_set_phase_taps(sdhci->parent, sdhci->phase_desc, taps); -- dev_dbg(dev, -- "Using taps [%d, %d] for [%d, %d] degrees of phase correction at %luHz (%d)\n", -- 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); -+ } ++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 */ ++}; + -+ sdhci_reset(host, mask); - } - --static void aspeed_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) -+static int aspeed_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) - { -- struct sdhci_pltfm_host *pltfm_host; -- unsigned long parent, bus; -+ struct sdhci_pltfm_host *pltfm_priv; - 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; - -- 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); -+ dev = mmc_dev(host->mmc); -+ pltfm_priv = sdhci_priv(host); -+ sdhci = sdhci_pltfm_priv(pltfm_priv); -+ sdc = sdhci->parent; - -- if (clock == 0) -- return; -+ out_phase = readl(sdc->regs + ASPEED_SDC_PHASE) & ASPEED_SDC_S0_PHASE_OUT; - -- 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; - - /* -- * Regarding the AST2600: -- * -- * If (EMMC12C[7:6], EMMC12C[15:8] == 0) then -- * period of SDCLK = period of SDMCLK. -- * -- * If (EMMC12C[7:6], EMMC12C[15:8] != 0) then -- * period of SDCLK = period of SDMCLK * 2 * (EMMC12C[7:6], EMMC[15:8]) -- * -- * If you keep EMMC12C[7:6] = 0 and EMMC12C[15:8] as one-hot, -- * 0x1/0x2/0x4/etc, you will find it is compatible to AST2400 or AST2500 -- * -- * 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; ++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, ++}; + -+ val = (out_phase | enable_mask | (inverted << ASPEED_SDC_S0_PHASE_IN_SHIFT)); ++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, ++}; + -+ /* 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); ++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 ++ }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, aspeed_usb_phy3_dt_ids); + -+ if (!mmc_send_tuning(host->mmc, opcode, NULL)) -+ break; ++static int aspeed_usb_phy3_init(struct phy *phy) ++{ ++ struct aspeed_usb_phy3 *phy3 = phy_get_drvdata(phy); ++ const struct aspeed_usb_phy3_model *model = phy3->model; ++ u32 val; ++ int timeout = 100; ++ int i, j; ++ ++ 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; + } ++ } + -+ /* 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); ++ val = readl(phy3->regs + model->phy3s00); + -+ if (mmc_send_tuning(host->mmc, opcode, NULL)) -+ break; -+ } ++ if (phy3->phy_ext_load_quirk) ++ val |= USB_PHY3_SRAM_EXT_LOAD; ++ else ++ val |= USB_PHY3_SRAM_BYPASS; ++ writel(val, phy3->regs + model->phy3s00); + -+ window = right - left; -+ pr_debug("tuning window[%d][%d~%d] = %d\n", edge, left, right, window); ++ /* 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); + -+ if (window > oldwindow) { -+ oldwindow = window; -+ center = (((right - 1) + left) / 2) | inverted; -+ } - } - -- 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; - -- sdhci_enable_clk(host, clk); --} -+ for (edge = 0; edge < 2; edge++) { -+ if (edge == 1) -+ inverted = ASPEED_SDHCI_TAP_PARAM_INVERT_CLK; - --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)); - -- 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); - --static void aspeed_sdhci_set_bus_width(struct sdhci_host *host, int width) --{ -- 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; -+ } - -- 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); - -- /* 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; -+ } - -- /* Set/clear 1 or 4 bit mode */ -- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); -- if (width == MMC_BUS_WIDTH_4) -- ctrl |= SDHCI_CTRL_4BITBUS; -- else -- 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); - --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; ++ /* 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(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; ++ ++ val = (ctrl_data[i].offset << 16) | (ctrl_data[i].value >> 16); ++ writel(val, phy3->regs + j); ++ j += 4; + } + } - -- 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); ++ dev_info(phy3->dev, "Initialized USB PHY3\n"); ++ return 0; +} + -+static void aspeed_sdhci_voltage_switch(struct sdhci_host *host) ++static const struct phy_ops aspeed_usb_phy3_phyops = { ++ .init = aspeed_usb_phy3_init, ++ .owner = THIS_MODULE, ++}; ++ ++static int aspeed_usb_phy3_probe(struct platform_device *pdev) +{ -+ mdelay(30); - } - - static const struct sdhci_ops aspeed_sdhci_ops = { - .read_l = aspeed_sdhci_readl, -- .set_clock = aspeed_sdhci_set_clock, -- .get_max_clock = aspeed_sdhci_get_max_clock, -+ .set_clock = sdhci_set_clock, -+ .get_max_clock = sdhci_pltfm_clk_get_max_clock, - .set_bus_width = aspeed_sdhci_set_bus_width, - .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, -- .reset = sdhci_reset, -+ .voltage_switch = aspeed_sdhci_voltage_switch, -+ .reset = aspeed_sdhci_reset, - .set_uhs_signaling = sdhci_set_uhs_signaling, -+ .platform_execute_tuning = aspeed_sdhci_execute_tuning, - }; - - static const struct sdhci_pltfm_data aspeed_sdhci_pdata = { - .ops = &aspeed_sdhci_ops, - .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, -+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, - }; - - static inline int aspeed_sdhci_calculate_slot(struct aspeed_sdhci *dev, -@@ -372,12 +362,6 @@ - int slot; - int ret; - -- aspeed_pdata = of_device_get_match_data(&pdev->dev); -- if (!aspeed_pdata) { -- dev_err(&pdev->dev, "Missing platform configuration data\n"); -- return -EINVAL; -- } -- - host = sdhci_pltfm_init(pdev, &aspeed_sdhci_pdata, sizeof(*dev)); - if (IS_ERR(host)) - return PTR_ERR(host); -@@ -395,14 +379,6 @@ - else if (slot >= 2) - return -EINVAL; - -- if (slot < dev->pdata->nr_phase_descs) { -- dev->phase_desc = &dev->pdata->phase_desc[slot]; -- } else { -- dev_info(&pdev->dev, -- "Phase control not supported for slot %d\n", slot); -- dev->phase_desc = NULL; -- } -- - 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 @@ - of_property_read_bool(np, "sd-uhs-sdr104")) { - aspeed_sdc_set_slot_capability(host, dev->parent, ASPEED_SDC_CAP1_1_8V, - true, slot); -- } -- -- if (of_property_read_bool(np, "sd-uhs-sdr104")) { - aspeed_sdc_set_slot_capability(host, dev->parent, ASPEED_SDC_CAP2_SDR104, - true, slot); -+ } else { -+ aspeed_sdc_set_slot_capability(host, dev->parent, ASPEED_SDC_CAP1_1_8V, -+ 0, slot); -+ aspeed_sdc_set_slot_capability(host, dev->parent, ASPEED_SDC_CAP2_SDR104, -+ 0, slot); - } - - pltfm_host->clk = devm_clk_get(&pdev->dev, NULL); -@@ -434,9 +412,6 @@ - if (ret) - goto err_sdhci_add; - -- if (dev->phase_desc) -- mmc_of_parse_clk_phase(&pdev->dev, &dev->phase_map); -- - ret = sdhci_add_host(host); - if (ret) - goto err_sdhci_add; -@@ -469,45 +444,11 @@ - .clk_div_start = 2, - }; - --static const struct aspeed_sdhci_phase_desc ast2600_sdhci_phase[] = { -- /* SDHCI/Slot 0 */ -- [0] = { -- .in = { -- .tap_mask = ASPEED_SDC_S0_PHASE_IN, -- .enable_mask = ASPEED_SDC_S0_PHASE_IN_EN, -- .enable_value = 1, -- }, -- .out = { -- .tap_mask = ASPEED_SDC_S0_PHASE_OUT, -- .enable_mask = ASPEED_SDC_S0_PHASE_OUT_EN, -- .enable_value = 3, -- }, -- }, -- /* SDHCI/Slot 1 */ -- [1] = { -- .in = { -- .tap_mask = ASPEED_SDC_S1_PHASE_IN, -- .enable_mask = ASPEED_SDC_S1_PHASE_IN_EN, -- .enable_value = 1, -- }, -- .out = { -- .tap_mask = ASPEED_SDC_S1_PHASE_OUT, -- .enable_mask = ASPEED_SDC_S1_PHASE_OUT_EN, -- .enable_value = 3, -- }, -- }, --}; -- --static const struct aspeed_sdhci_pdata ast2600_sdhci_pdata = { -- .clk_div_start = 1, -- .phase_desc = ast2600_sdhci_phase, -- .nr_phase_descs = ARRAY_SIZE(ast2600_sdhci_phase), --}; -- - static const struct of_device_id aspeed_sdhci_of_match[] = { - { .compatible = "aspeed,ast2400-sdhci", .data = &ast2400_sdhci_pdata, }, -- { .compatible = "aspeed,ast2500-sdhci", .data = &ast2400_sdhci_pdata, }, -- { .compatible = "aspeed,ast2600-sdhci", .data = &ast2600_sdhci_pdata, }, -+ { .compatible = "aspeed,ast2500-sdhci", }, -+ { .compatible = "aspeed,ast2600-sdhci", }, -+ { .compatible = "aspeed,ast2600-emmc", }, - { } - }; - MODULE_DEVICE_TABLE(of, aspeed_sdhci_of_match); -@@ -522,11 +463,22 @@ - .remove_new = aspeed_sdhci_remove, - }; - -+static const struct of_device_id aspeed_sdc_of_match[] = { -+ { .compatible = "aspeed,ast2400-sd-controller", }, -+ { .compatible = "aspeed,ast2500-sd-controller", }, -+ { .compatible = "aspeed,ast2600-sd-controller", .data = &ast2600_sdc_info}, -+ { } -+}; ++ struct aspeed_usb_phy3 *phy3; ++ struct device *dev; ++ struct phy_provider *provider; ++ struct phy *phy; ++ struct device_node *node = pdev->dev.of_node; ++ struct clk *clk; ++ struct reset_control *rst; ++ int rc = 0; + -+MODULE_DEVICE_TABLE(of, aspeed_sdc_of_match); ++ dev = &pdev->dev; + - static int aspeed_sdc_probe(struct platform_device *pdev) - - { - struct device_node *parent, *child; - struct aspeed_sdc *sdc; -+ const struct of_device_id *match = NULL; -+ const struct aspeed_sdc_info *info = NULL; - int ret; - - sdc = devm_kzalloc(&pdev->dev, sizeof(*sdc), GFP_KERNEL); -@@ -535,6 +487,23 @@ - - spin_lock_init(&sdc->lock); - -+ match = of_match_device(aspeed_sdc_of_match, &pdev->dev); -+ if (!match) -+ return -ENODEV; ++ phy3 = devm_kzalloc(dev, sizeof(*phy3), GFP_KERNEL); ++ if (!phy3) ++ return -ENOMEM; + -+ if (match->data) -+ info = match->data; ++ phy3->dev = dev; + -+ if (info) { -+ if (info->flag & PROBE_AFTER_ASSET_DEASSERT) { -+ sdc->rst = devm_reset_control_get(&pdev->dev, NULL); -+ if (!IS_ERR(sdc->rst)) { -+ reset_control_assert(sdc->rst); -+ reset_control_deassert(sdc->rst); -+ } -+ } ++ phy3->model = of_device_get_match_data(dev); ++ if (IS_ERR(phy3->model)) { ++ dev_err(dev, "Couldn't get model data\n"); ++ return -ENODEV; + } + - sdc->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(sdc->clk)) - return PTR_ERR(sdc->clk); -@@ -579,15 +548,6 @@ - clk_disable_unprepare(sdc->clk); - } - --static const struct of_device_id aspeed_sdc_of_match[] = { -- { .compatible = "aspeed,ast2400-sd-controller", }, -- { .compatible = "aspeed,ast2500-sd-controller", }, -- { .compatible = "aspeed,ast2600-sd-controller", }, -- { } --}; -- --MODULE_DEVICE_TABLE(of, aspeed_sdc_of_match); -- - 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 2026-04-08 18:03:33.980966943 +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 2026-04-08 18:03:38.662881549 +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 2026-04-08 18:03:48.110708974 +0000 -@@ -0,0 +1,1720 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* ASPEED CAN device driver -+ * -+ * Copyright (C) 2023 ASPEED Inc. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DRIVER_NAME "aspeed_can" -+ -+#define CAN_AC_SEG (0x0004) /* classic can seg */ -+#define CAN_FD_SEG (0x0008) /* can fd seg */ -+#define CAN_BITITME (0x0010) /* prescaler */ -+#define CAN_INTF (0x0014) /* can interrupt flag */ -+#define CAN_INTE (0x0018) /* can interrupt enabled */ -+#define CAN_TSTAT (0x001c) /* can transmit status */ -+ -+#define CAN_CTRL (0x0028) -+#define CAN_ERR_STAT (0x002c) /* err ctrl and rx/tx err status */ -+ -+#define CAN_RBUF (0x0070) /* receive buffer registers 0x070-0x88b(*/ -+#define CAN_TBUF (0x0890) /* transmit buffer registers 0x890-0x10ab */ -+ -+#define CAN_RBUF_ID (CAN_RBUF + 0x0000) -+#define CAN_RBUF_CTL (CAN_RBUF + 0x0004) -+#define CAN_RBUF_TYPE (CAN_RBUF + 0x0008) -+#define CAN_RBUF_ACF (CAN_RBUF + 0x000C) -+#define CAN_RBUF_DATA (CAN_RBUF + 0x0010) -+ -+#define CAN_TBUF_ID (CAN_TBUF + 0x0000) -+#define CAN_TBUF_CTL (CAN_TBUF + 0x0004) -+#define CAN_TBUF_TYPE (CAN_TBUF + 0x0008) -+#define CAN_TBUF_ACF (CAN_TBUF + 0x000C) -+#define CAN_TBUF_DATA (CAN_TBUF + 0x0010) -+ -+#define CAN_MODE_CONFIG (0x1100) -+ -+#define CAN_TBUF_MIRROR (0x1190) -+#define CAN_TBUF_READ_ID (CAN_TBUF_MIRROR + 0x0000) -+#define CAN_TBUF_READ_CTL (CAN_TBUF_MIRROR + 0x0004) -+#define CAN_TBUF_READ_TYPE (CAN_TBUF_MIRROR + 0x0008) -+#define CAN_TBUF_READ_ACF (CAN_TBUF_MIRROR + 0x000C) -+#define CAN_TBUF_READ_DATA (CAN_TBUF_MIRROR + 0x0010) -+ -+/* CAN_AC_SEG(0x0004) bit description */ -+#define CAN_TIMING_AC_SEG1_MASK GENMASK(8, 0) -+#define CAN_TIMING_AC_SEG2_MASK GENMASK(22, 16) -+#define CAN_TIMING_AC_SJW_MASK GENMASK(30, 24) -+ -+#define CAN_TIMING_AC_SEG1_BITOFF 0 -+#define CAN_TIMING_AC_SEG2_BITOFF 16 -+#define CAN_TIMING_AC_SJW_BITOFF 24 -+ -+/* CAN_FD_SEG(0x0008) bit description */ -+#define CAN_TIMING_FD_SEG1_MASK GENMASK(7, 0) -+#define CAN_TIMING_FD_SEG2_MASK GENMASK(22, 16) -+#define CAN_TIMING_FD_SJW_MASK GENMASK(30, 24) -+ -+#define CAN_TIMING_FD_SEG1_BITOFF 0 -+#define CAN_TIMING_FD_SEG2_BITOFF 16 -+#define CAN_TIMING_FD_SJW_BITOFF 24 -+ -+/* CAN_BITTIME(0x0010) bit description */ -+#define CAN_TIMING_PRESC_MASK GENMASK(4, 0) -+#define CAN_TIMING_PRESC_BITOFF 0 -+#define CAN_TIMING_FD_SSPOFF_MASK GENMASK(15, 8) -+#define CAN_TIMING_FD_SSPOFF_BITOFF 8 -+ -+/* CAN_INTF(0x0014) bit description */ -+#define CAN_INT_EIF_BIT BIT(1) /* error interrupt flag */ -+#define CAN_INT_TSIF_BIT BIT(2) /* transmission secondary interrupt flag */ -+#define CAN_INT_TPIF_BIT BIT(3) /* transmission primary interrupt flag */ -+#define CAN_INT_RAFIF_BIT BIT(4) /* RB almost full interrupt flag */ -+#define CAN_INT_RFIF_BIT BIT(5) /* RB full interrupt flag */ -+#define CAN_INT_ROIF_BIT BIT(6) /* RB overflow interrupt flag */ -+#define CAN_INT_RIF_BIT BIT(7) /* receive interrupt flag */ -+#define CAN_INT_BEIF_BIT BIT(8) /* bus error interrupt flag */ -+#define CAN_INT_ALIF_BIT BIT(9) /* arbitration loss interrupt flag */ -+#define CAN_INT_EPIF_BIT BIT(10) /* error passive interrupt flag */ -+#define CAN_EPASS_BIT BIT(30) /* check if device is error passive */ -+#define CAN_INT_EWARN_BIT BIT(31) /* error Warning limit reached */ -+ -+/* CAN_INTE(0x0018) bit description */ -+#define CAN_INT_EIE_BIT BIT(1) /* error interrupt enable */ -+#define CAN_INT_TSIE_BIT BIT(2) /* transmission secondary interrupt enable */ -+#define CAN_INT_TPIE_BIT BIT(3) /* transmission secondary interrupt enable */ -+#define CAN_INT_RAFIE_BIT BIT(4) /* RB almost full interrupt enable */ -+#define CAN_INT_RFIE_BIT BIT(5) /* RB full interrupt enable */ -+#define CAN_INT_ROIE_BIT BIT(6) /* RB overflow interrupt enable */ -+#define CAN_INT_RIE_BIT BIT(7) /* receive interrupt enable */ -+#define CAN_INT_BEIE_BIT BIT(8) /* bus error interrupt enable */ -+#define CAN_INT_ALIE_BIT BIT(9) /* arbitration loss interrupt enable */ -+#define CAN_INT_EPIE_BIT BIT(10) /* error passive interrupt enable */ -+ -+/* CAN_TSTAT(0x001C) bit description */ -+#define CAN_TSTAT1_MASK GENMASK(10, 8) -+#define CAN_TSTAT1_BITOFF 8 -+#define CAN_TSTAT2_HANDLE_MASK GENMASK(23, 16) -+#define CAN_TSTAT2_HANDLE_BITOFF 16 -+#define CAN_TSTAT2_MASK GENMASK(26, 24) -+#define CAN_TSTAT2_BITOFF 24 -+ -+/* CAN_CTRL(0x0028) bit description */ -+#define CAN_CTRL_BUSOFF_BIT BIT(0) -+#define CAN_CTRL_LBMIMOD_BIT BIT(5) /* set loop back mode, internal */ -+#define CAN_CTRL_LBMEMOD_BIT BIT(6) /* set loop back mode, external */ -+#define CAN_CTRL_RST_BIT BIT(7) /* set reset bit */ -+#define CAN_CTRL_TSALL_BIT BIT(9) /* transmit secondary all frame */ -+#define CAN_CTRL_TSONE_BIT BIT(10) /* transmit secondary one frame */ -+#define CAN_CTRL_TPE_BIT BIT(12) /* transmit primary enable */ -+#define CAN_CTRL_STBY_BIT BIT(13) /* transceiver standby */ -+#define CAN_CTRL_TBSEL_BIT BIT(15) /* transmit buffer select */ -+#define CAN_CTRL_TSSTAT_MASK GENMASK(17, 16) /* Transmission secondary status bits */ -+#define CAN_CTRL_TSFF_BIT BIT(18) /* transmit secondary buffer full flag */ -+#define CAN_CTRL_TTBM_BIT BIT(20) /* set TTTBM as 1->full TTCAN mode */ -+#define CAN_CTRL_TSMODE_BIT BIT(21) /* set TSMODE as 1->FIFO mode */ -+#define CAN_CTRL_TSNEXT_BIT BIT(22) /* transmit buffer secondary NEXT */ -+#define CAN_CTRL_RSTAT_NOT_EMPTY_MASKT GENMASK(25, 24) -+#define CAN_CTRL_RREL_BIT BIT(28) /* receive buffer release */ -+#define CAN_CTRL_SACK_BIT BIT(31) /* self-ack mode */ -+ -+#define STB_IS_EMPTY 0x0 -+ -+/* CAN_ERR(0x002c) bit description */ -+#define CAN_ERR_EWL_MASK GENMASK(3, 0) /* programmable error warning limit */ -+#define CAN_ERR_EWL_BITOFF 0 -+#define CAN_ERR_AFWL_MASK GENMASK(7, 4) /* receive buffer almost full warning limit */ -+#define CAN_ERR_AFWL_BITOFF 4 -+#define CAN_ERR_ALC_MASK GENMASK(12, 8) /* arbitration lost capture */ -+#define CAN_ERR_ALC_BITOFF 8 -+#define CAN_ERR_KOER_MASK GENMASK(15, 13) /* kind of error */ -+#define CAN_ERR_KOER_BITOFF 13 -+#define CAN_ERR_RECNT_MASK GENMASK(23, 16) /* receive error count */ -+#define CAN_ERR_RECNT_BITOFF 16 -+#define CAN_ERR_TECNT_MASK GENMASK(31, 24) /* transmit error count */ -+#define CAN_ERR_TECNT_BITOFF 24 -+ -+/* CAN BUF bit description*/ -+#define CAN_BUF_ID_BFF_MASK GENMASK(28, 18) /* frame identifier */ -+#define CAN_BUF_ID_BFF_BITOFF 18 -+#define CAN_BUF_ID_EFF_MASK GENMASK(28, 0) /* identifier extension */ -+#define CAN_BUF_ID_EFF_BITOFF 0 -+#define CAN_BUF_DLC_MASK GENMASK(10, 0) /* data length code */ -+#define CAN_BUF_IDE_BIT BIT(16) /* identifier extension */ -+#define CAN_BUF_FDF_BIT BIT(17) /* CAN FD frame format */ -+#define CAN_BUF_BRS_BIT BIT(18) /* CAN FD bit rate switch enable */ -+#define CAN_BUF_RMF_BIT BIT(20) /* remot frame */ -+#define CAN_BUF_HANDLE_BITOFF 24 -+ -+#define KOER_BIT_ERROR_MASK (BIT(0)) -+#define KOER_FORM_ERROR_MASK (BIT(1)) -+#define KOER_STUFF_ERROR_MASK (BIT(1) | BIT(0)) -+#define KOER_ACK_ERROR_MASK (BIT(2)) -+#define KOER_CRC_ERROR_MASK (BIT(2) | BIT(0)) -+#define KOER_OTH_ERROR_MASK (BIT(2) | BIT(1)) -+ -+#define STAT_AFWL 0x04 -+#define STAT_EWL 0x0b -+ -+#define STB_IDX_RING_SZ 3 ++ clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(clk)) ++ return PTR_ERR(clk); + -+#define PTB_MODE 0x01 -+#define STB_MODE 0x02 ++ rc = clk_prepare_enable(clk); ++ if (rc) { ++ dev_err(dev, "Unable to enable clock (%d)\n", rc); ++ return rc; ++ } + -+#define STB_TX_MODE_ALL 0x01 /* secondary tx buffer mode */ -+#define STB_TX_MODE_ONE 0x02 /* secondary tx buffer mode */ -+#define STB_POLICY_FIFO 0x10 /* secondary tx buffer fifo mode */ -+#define STB_POLICY_PRIO 0x20 /* secondary tx buffer prioity mode */ ++ 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; + -+#define STB_INVALID_HANDLE_VAL 0xffffffff -+#define STB_INVALID_SKB_IDX 0xffffffff ++ phy3->regs = of_iomap(node, 0); + -+/* SW flag */ -+#define ASPEED_CAN_INTERNEL_LOOPBACK 0x00000001 ++ phy3->phy_ext_load_quirk = ++ device_property_read_bool(dev, "aspeed,phy_ext_load_quirk"); + -+struct can_stb_ring_obj { -+ u32 idx; -+ u32 skb_idx; -+ u32 handle; -+ struct can_stb_ring_obj *next; -+}; ++ phy = devm_phy_create(dev, NULL, &aspeed_usb_phy3_phyops); ++ if (IS_ERR(phy)) { ++ dev_err(dev, "failed to create PHY\n"); ++ return PTR_ERR(phy); ++ } + -+struct aspeed_can_priv { -+ /* Fix the location of "struct can_priv can" -+ * in this struct. -+ */ -+ struct can_priv can; -+ void __iomem *reg_base; -+ struct device *dev; -+ /* Lock for synchronizing TX interrupt handling */ -+ spinlock_t tx_lock; -+ struct can_stb_ring_obj *stb_ring; -+ struct can_stb_ring_obj *head_ptr; -+ struct can_stb_ring_obj *tail_ptr; -+ u32 tx_max; -+ struct napi_struct napi; -+ struct clk *clk; -+ struct reset_control *reset; -+ u32 tb_mode; -+ u32 stb_mode_policy; -+ u32 frame_handle; -+ u32 flag; -+}; ++ provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); ++ if (IS_ERR(provider)) ++ return PTR_ERR(provider); + -+static const struct can_bittiming_const aspeed_can_bittiming_const = { -+ .name = DRIVER_NAME, -+ .tseg1_min = 2, -+ .tseg1_max = 513, -+ .tseg2_min = 1, -+ .tseg2_max = 128, -+ .sjw_max = 128, -+ .brp_min = 1, -+ .brp_max = 128, -+ .brp_inc = 1, -+}; ++ phy_set_drvdata(phy, phy3); + -+static const struct can_bittiming_const aspeed_canfd_bittiming_const = { -+ .name = DRIVER_NAME, -+ .tseg1_min = 2, -+ .tseg1_max = 257, -+ .tseg2_min = 1, -+ .tseg2_max = 128, -+ .sjw_max = 128, -+ .brp_min = 1, -+ .brp_max = 128, -+ .brp_inc = 1, -+}; ++ dev_info(phy3->dev, "Probed USB PHY3\n"); + -+inline void aspeed_can_set_bit(struct aspeed_can_priv *priv, -+ u32 reg_off, u32 bit) -+{ -+ u32 reg_val; ++ return 0; + -+ reg_val = readl(priv->reg_base + reg_off); -+ reg_val |= bit; -+ writel(reg_val, priv->reg_base + reg_off); ++err: ++ if (clk) ++ clk_disable_unprepare(clk); ++ return rc; +} + -+inline void aspeed_can_clr_bit(struct aspeed_can_priv *priv, -+ u32 reg_off, u32 bit) ++static void aspeed_usb_phy3_remove(struct platform_device *pdev) +{ -+ u32 reg_val; -+ -+ reg_val = readl(priv->reg_base + reg_off); -+ reg_val &= ~(bit); -+ writel(reg_val, priv->reg_base + reg_off); +} + -+inline void aspeed_can_clr_irq_bits(struct aspeed_can_priv *priv, -+ u32 reg_off, u32 bits) -+{ -+ writel(bits, priv->reg_base + reg_off); -+} ++static struct platform_driver aspeed_usb_phy3_driver = { ++ .probe = aspeed_usb_phy3_probe, ++ .remove = aspeed_usb_phy3_remove, ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = aspeed_usb_phy3_dt_ids, ++ }, ++}; ++module_platform_driver(aspeed_usb_phy3_driver); + -+static bool aspeed_can_check_reset_mode(struct net_device *ndev) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ -+ if (!(readl(priv->reg_base + CAN_CTRL) & CAN_CTRL_RST_BIT)) -+ return false; -+ -+ return true; -+} -+ -+static void aspeed_can_stb_ring_obj_init(struct net_device *ndev) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ int i; -+ -+ for (i = 0; i < STB_IDX_RING_SZ; i++) { -+ priv->stb_ring[i].idx = i + 1; -+ priv->stb_ring[i].skb_idx = i + 1; -+ priv->stb_ring[i].handle = STB_INVALID_HANDLE_VAL; -+ -+ if (i == STB_IDX_RING_SZ - 1) { -+ priv->stb_ring[i].next = &priv->stb_ring[0]; -+ } else { -+ priv->stb_ring[i].next = -+ &priv->stb_ring[i + 1]; -+ } -+ } -+ -+ priv->head_ptr = &priv->stb_ring[0]; -+ priv->tail_ptr = &priv->stb_ring[0]; -+} -+ -+static u32 aspeed_can_get_skb_idx(struct net_device *ndev, -+ u32 handle) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ struct can_stb_ring_obj *tmp_ptr = priv->tail_ptr; -+ -+ if (tmp_ptr->handle == handle) -+ return tmp_ptr->skb_idx; -+ -+ tmp_ptr = priv->tail_ptr->next; -+ -+ while (tmp_ptr != priv->head_ptr) { -+ if (tmp_ptr->handle == handle) -+ return tmp_ptr->skb_idx; -+ tmp_ptr = tmp_ptr->next; -+ } -+ -+ return STB_INVALID_SKB_IDX; -+} -+ -+static int aspeed_can_drop_ring_obj(struct net_device *ndev, -+ u32 handle) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ struct can_stb_ring_obj *tmp_ptr = priv->tail_ptr; -+ u32 tmp_skb_idx; -+ -+ if (tmp_ptr->handle == handle) { -+ /* keep original skb idx */ -+ tmp_ptr->handle = STB_INVALID_HANDLE_VAL; -+ priv->tail_ptr = priv->tail_ptr->next; -+ return 0; -+ } -+ -+ tmp_ptr = priv->tail_ptr->next; -+ -+ while (tmp_ptr != priv->head_ptr) { -+ if (tmp_ptr->handle == handle) { -+ tmp_skb_idx = tmp_ptr->skb_idx; -+ tmp_ptr->handle = priv->tail_ptr->handle; -+ tmp_ptr->skb_idx = priv->tail_ptr->skb_idx; -+ -+ priv->tail_ptr->skb_idx = tmp_skb_idx; -+ priv->tail_ptr->handle = STB_INVALID_HANDLE_VAL; -+ priv->tail_ptr = priv->tail_ptr->next; -+ return 0; -+ } -+ -+ tmp_ptr = tmp_ptr->next; -+ } -+ -+ return -1; -+} -+ -+static u32 aspeed_can_get_frame_num(struct net_device *ndev) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ struct can_stb_ring_obj *tmp_ptr = priv->tail_ptr; -+ u32 len = 0; -+ -+ if (tmp_ptr == priv->head_ptr) -+ return STB_IDX_RING_SZ; -+ -+ while (tmp_ptr != priv->head_ptr) { -+ len++; -+ tmp_ptr = tmp_ptr->next; -+ } -+ -+ return len; -+} -+ -+static int aspeed_can_set_reset_mode(struct net_device *ndev) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ unsigned long timeout; -+ -+ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_RST_BIT); -+ -+ timeout = jiffies + (1 * HZ); -+ while (!aspeed_can_check_reset_mode(ndev)) { -+ if (time_after(jiffies, timeout)) { -+ netdev_warn(ndev, "timed out for config mode\n"); -+ return -ETIMEDOUT; -+ } -+ -+ usleep_range(500, 10000); -+ } ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Joe Wang "); +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 +@@ -31,3 +31,11 @@ + help + Say Y here to enable pin controller support for Aspeed's 6th + generation SoCs. GPIO is provided by a separate GPIO driver. + -+ aspeed_can_stb_ring_obj_init(ndev); ++config PINCTRL_ASPEED_G7 ++ bool "Aspeed G7 SoC pin control" ++ depends on (ARCH_ASPEED || COMPILE_TEST) && OF ++ select PINCTRL_ASPEED ++ help ++ 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 +@@ -6,3 +6,4 @@ + obj-$(CONFIG_PINCTRL_ASPEED_G4) += pinctrl-aspeed-g4.o + obj-$(CONFIG_PINCTRL_ASPEED_G5) += pinctrl-aspeed-g5.o + obj-$(CONFIG_PINCTRL_ASPEED_G6) += pinctrl-aspeed-g6.o ++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 +@@ -17,6 +17,8 @@ + #include "../pinctrl-utils.h" + #include "pinctrl-aspeed.h" + ++#define SCU040 0x040 /* Reset Control Set 1 */ ++#define SCU0C8 0x0C8 /* Debug Control */ + #define SCU400 0x400 /* Multi-function Pin Control #1 */ + #define SCU404 0x404 /* Multi-function Pin Control #2 */ + #define SCU40C 0x40C /* Multi-function Pin Control #3 */ +@@ -31,6 +33,7 @@ + #define SCU450 0x450 /* Multi-function Pin Control #14 */ + #define SCU454 0x454 /* Multi-function Pin Control #15 */ + #define SCU458 0x458 /* Multi-function Pin Control #16 */ ++#define SCU470 0x470 + #define SCU4B0 0x4B0 /* Multi-function Pin Control #17 */ + #define SCU4B4 0x4B4 /* Multi-function Pin Control #18 */ + #define SCU4B8 0x4B8 /* Multi-function Pin Control #19 */ +@@ -46,13 +49,16 @@ + #define SCU630 0x630 /* Disable GPIO Internal Pull-Down #4 */ + #define SCU634 0x634 /* Disable GPIO Internal Pull-Down #5 */ + #define SCU638 0x638 /* Disable GPIO Internal Pull-Down #6 */ ++#define SCU650 0x650 /* Driving Strength */ + #define SCU690 0x690 /* Multi-function Pin Control #24 */ + #define SCU694 0x694 /* Multi-function Pin Control #25 */ ++#define SCU698 0x698 /* Multi-function Pin Control #26 */ + #define SCU69C 0x69C /* Multi-function Pin Control #27 */ + #define SCU6D0 0x6D0 /* Multi-function Pin Control #29 */ + #define SCUC20 0xC20 /* PCIE configuration Setting Control */ ++#define SCUC24 0xC24 /* BMC MMIO Decode Setting */ + +-#define ASPEED_G6_NR_PINS 256 ++#define ASPEED_G6_NR_PINS 258 + + #define M24 0 + SIG_EXPR_LIST_DECL_SESG(M24, MDC3, MDIO3, SIG_DESC_SET(SCU410, 0)); +@@ -171,81 +177,93 @@ + + #define H24 16 + SIG_EXPR_LIST_DECL_SESG(H24, RGMII3TXCK, RGMII3, SIG_DESC_SET(SCU410, 16), +- SIG_DESC_SET(SCU510, 0)); ++ SIG_DESC_SET(SCU510, 0)); + SIG_EXPR_LIST_DECL_SESG(H24, RMII3RCLKO, RMII3, SIG_DESC_SET(SCU410, 16), +- SIG_DESC_CLEAR(SCU510, 0)); +-PIN_DECL_2(H24, GPIOC0, RGMII3TXCK, RMII3RCLKO); ++ SIG_DESC_CLEAR(SCU510, 0)); ++SIG_EXPR_LIST_DECL_SESG(H24, VPA_B0, VPA, SIG_DESC_CLEAR(SCU410, 16)); ++PIN_DECL_3(H24, GPIOC0, RGMII3TXCK, RMII3RCLKO, VPA_B0); + + #define J22 17 + SIG_EXPR_LIST_DECL_SESG(J22, RGMII3TXCTL, RGMII3, SIG_DESC_SET(SCU410, 17), +- SIG_DESC_SET(SCU510, 0)); ++ SIG_DESC_SET(SCU510, 0)); + SIG_EXPR_LIST_DECL_SESG(J22, RMII3TXEN, RMII3, SIG_DESC_SET(SCU410, 17), +- SIG_DESC_CLEAR(SCU510, 0)); +-PIN_DECL_2(J22, GPIOC1, RGMII3TXCTL, RMII3TXEN); ++ SIG_DESC_CLEAR(SCU510, 0)); ++SIG_EXPR_LIST_DECL_SESG(J22, VPA_B1, VPA, SIG_DESC_CLEAR(SCU410, 17)); ++PIN_DECL_3(J22, GPIOC1, RGMII3TXCTL, RMII3TXEN, VPA_B1); + + #define H22 18 + SIG_EXPR_LIST_DECL_SESG(H22, RGMII3TXD0, RGMII3, SIG_DESC_SET(SCU410, 18), +- SIG_DESC_SET(SCU510, 0)); ++ SIG_DESC_SET(SCU510, 0)); + SIG_EXPR_LIST_DECL_SESG(H22, RMII3TXD0, RMII3, SIG_DESC_SET(SCU410, 18), +- SIG_DESC_CLEAR(SCU510, 0)); +-PIN_DECL_2(H22, GPIOC2, RGMII3TXD0, RMII3TXD0); ++ SIG_DESC_CLEAR(SCU510, 0)); ++SIG_EXPR_LIST_DECL_SESG(H22, VPA_B2, VPA, SIG_DESC_CLEAR(SCU410, 18)); ++PIN_DECL_3(H22, GPIOC2, RGMII3TXD0, RMII3TXD0, VPA_B2); + + #define H23 19 + SIG_EXPR_LIST_DECL_SESG(H23, RGMII3TXD1, RGMII3, SIG_DESC_SET(SCU410, 19), +- SIG_DESC_SET(SCU510, 0)); ++ SIG_DESC_SET(SCU510, 0)); + SIG_EXPR_LIST_DECL_SESG(H23, RMII3TXD1, RMII3, SIG_DESC_SET(SCU410, 19), +- SIG_DESC_CLEAR(SCU510, 0)); +-PIN_DECL_2(H23, GPIOC3, RGMII3TXD1, RMII3TXD1); ++ SIG_DESC_CLEAR(SCU510, 0)); ++SIG_EXPR_LIST_DECL_SESG(H23, VPA_B3, VPA, SIG_DESC_CLEAR(SCU410, 19)); ++PIN_DECL_3(H23, GPIOC3, RGMII3TXD1, RMII3TXD1, VPA_B3); + + #define G22 20 + SIG_EXPR_LIST_DECL_SESG(G22, RGMII3TXD2, RGMII3, SIG_DESC_SET(SCU410, 20), +- SIG_DESC_SET(SCU510, 0)); +-PIN_DECL_1(G22, GPIOC4, RGMII3TXD2); ++ SIG_DESC_SET(SCU510, 0)); ++SIG_EXPR_LIST_DECL_SESG(G22, VPA_B4, VPA, SIG_DESC_CLEAR(SCU410, 20)); ++PIN_DECL_2(G22, GPIOC4, RGMII3TXD2, VPA_B4); + + #define F22 21 + SIG_EXPR_LIST_DECL_SESG(F22, RGMII3TXD3, RGMII3, SIG_DESC_SET(SCU410, 21), +- SIG_DESC_SET(SCU510, 0)); +-PIN_DECL_1(F22, GPIOC5, RGMII3TXD3); ++ SIG_DESC_SET(SCU510, 0)); ++SIG_EXPR_LIST_DECL_SESG(F22, VPA_B5, VPA, SIG_DESC_CLEAR(SCU410, 21)); ++PIN_DECL_2(F22, GPIOC5, RGMII3TXD3, VPA_B5); + + #define G23 22 + SIG_EXPR_LIST_DECL_SESG(G23, RGMII3RXCK, RGMII3, SIG_DESC_SET(SCU410, 22), +- SIG_DESC_SET(SCU510, 0)); ++ SIG_DESC_SET(SCU510, 0)); + SIG_EXPR_LIST_DECL_SESG(G23, RMII3RCLKI, RMII3, SIG_DESC_SET(SCU410, 22), +- SIG_DESC_CLEAR(SCU510, 0)); +-PIN_DECL_2(G23, GPIOC6, RGMII3RXCK, RMII3RCLKI); ++ SIG_DESC_CLEAR(SCU510, 0)); ++SIG_EXPR_LIST_DECL_SESG(G23, VPAPCLK, VPA, SIG_DESC_CLEAR(SCU410, 22)); ++PIN_DECL_3(G23, GPIOC6, RGMII3RXCK, RMII3RCLKI, VPAPCLK); + + #define G24 23 + SIG_EXPR_LIST_DECL_SESG(G24, RGMII3RXCTL, RGMII3, SIG_DESC_SET(SCU410, 23), +- SIG_DESC_SET(SCU510, 0)); +-PIN_DECL_1(G24, GPIOC7, RGMII3RXCTL); ++ SIG_DESC_SET(SCU510, 0)); ++SIG_EXPR_LIST_DECL_SESG(G24, VPA_B6, VPA, SIG_DESC_CLEAR(SCU410, 23)); ++PIN_DECL_2(G24, GPIOC7, RGMII3RXCTL, VPA_B6); + + #define F23 24 + SIG_EXPR_LIST_DECL_SESG(F23, RGMII3RXD0, RGMII3, SIG_DESC_SET(SCU410, 24), +- SIG_DESC_SET(SCU510, 0)); ++ SIG_DESC_SET(SCU510, 0)); + SIG_EXPR_LIST_DECL_SESG(F23, RMII3RXD0, RMII3, SIG_DESC_SET(SCU410, 24), +- SIG_DESC_CLEAR(SCU510, 0)); +-PIN_DECL_2(F23, GPIOD0, RGMII3RXD0, RMII3RXD0); ++ SIG_DESC_CLEAR(SCU510, 0)); ++SIG_EXPR_LIST_DECL_SESG(F23, VPA_B7, VPA, SIG_DESC_CLEAR(SCU410, 24)); ++PIN_DECL_3(F23, GPIOD0, RGMII3RXD0, RMII3RXD0, VPA_B7); + + #define F26 25 + SIG_EXPR_LIST_DECL_SESG(F26, RGMII3RXD1, RGMII3, SIG_DESC_SET(SCU410, 25), +- SIG_DESC_SET(SCU510, 0)); ++ SIG_DESC_SET(SCU510, 0)); + SIG_EXPR_LIST_DECL_SESG(F26, RMII3RXD1, RMII3, SIG_DESC_SET(SCU410, 25), +- SIG_DESC_CLEAR(SCU510, 0)); +-PIN_DECL_2(F26, GPIOD1, RGMII3RXD1, RMII3RXD1); ++ SIG_DESC_CLEAR(SCU510, 0)); ++SIG_EXPR_LIST_DECL_SESG(F26, VPA_G0, VPA, SIG_DESC_CLEAR(SCU410, 25)); ++PIN_DECL_3(F26, GPIOD1, RGMII3RXD1, RMII3RXD1, VPA_G0); + + #define F25 26 + SIG_EXPR_LIST_DECL_SESG(F25, RGMII3RXD2, RGMII3, SIG_DESC_SET(SCU410, 26), +- SIG_DESC_SET(SCU510, 0)); ++ SIG_DESC_SET(SCU510, 0)); + SIG_EXPR_LIST_DECL_SESG(F25, RMII3CRSDV, RMII3, SIG_DESC_SET(SCU410, 26), +- SIG_DESC_CLEAR(SCU510, 0)); +-PIN_DECL_2(F25, GPIOD2, RGMII3RXD2, RMII3CRSDV); ++ SIG_DESC_CLEAR(SCU510, 0)); ++SIG_EXPR_LIST_DECL_SESG(F25, VPA_G1, VPA, SIG_DESC_CLEAR(SCU410, 26)); ++PIN_DECL_3(F25, GPIOD2, RGMII3RXD2, RMII3CRSDV, VPA_G1); + + #define E26 27 + SIG_EXPR_LIST_DECL_SESG(E26, RGMII3RXD3, RGMII3, SIG_DESC_SET(SCU410, 27), +- SIG_DESC_SET(SCU510, 0)); ++ SIG_DESC_SET(SCU510, 0)); + SIG_EXPR_LIST_DECL_SESG(E26, RMII3RXER, RMII3, SIG_DESC_SET(SCU410, 27), +- SIG_DESC_CLEAR(SCU510, 0)); +-PIN_DECL_2(E26, GPIOD3, RGMII3RXD3, RMII3RXER); ++ SIG_DESC_CLEAR(SCU510, 0)); ++SIG_EXPR_LIST_DECL_SESG(E26, VPA_G2, VPA, SIG_DESC_CLEAR(SCU410, 27)); ++PIN_DECL_3(E26, GPIOD3, RGMII3RXD3, RMII3RXER, VPA_G2); + + FUNC_GROUP_DECL(RGMII3, H24, J22, H22, H23, G22, F22, G23, G24, F23, F26, F25, + E26); +@@ -259,7 +277,9 @@ + SIG_DESC_SET(SCU510, 1)); + SIG_EXPR_LIST_DECL_SESG(F24, RMII4RCLKO, RMII4, SIG_DESC_SET(SCU4B0, 28), + SIG_DESC_CLEAR(SCU510, 1)); +-PIN_DECL_3(F24, GPIOD4, NCTS3, RGMII4TXCK, RMII4RCLKO); ++SIG_EXPR_LIST_DECL_SESG(F24, VPA_G3, VPA, SIG_DESC_CLEAR(SCU410, 28), ++ SIG_DESC_CLEAR(SCU4B0, 28)); ++PIN_DECL_4(F24, GPIOD4, NCTS3, RGMII4TXCK, RMII4RCLKO, VPA_G3); + FUNC_GROUP_DECL(NCTS3, F24); + + #define E23 29 +@@ -268,7 +288,9 @@ + SIG_DESC_SET(SCU510, 1)); + SIG_EXPR_LIST_DECL_SESG(E23, RMII4TXEN, RMII4, SIG_DESC_SET(SCU4B0, 29), + SIG_DESC_CLEAR(SCU510, 1)); +-PIN_DECL_3(E23, GPIOD5, NDCD3, RGMII4TXCTL, RMII4TXEN); ++SIG_EXPR_LIST_DECL_SESG(E23, VPA_G4, VPA, SIG_DESC_CLEAR(SCU410, 29), ++ SIG_DESC_CLEAR(SCU4B0, 29)); ++PIN_DECL_4(E23, GPIOD5, NDCD3, RGMII4TXCTL, RMII4TXEN, VPA_G4); + FUNC_GROUP_DECL(NDCD3, E23); + + #define E24 30 +@@ -277,7 +299,9 @@ + SIG_DESC_SET(SCU510, 1)); + SIG_EXPR_LIST_DECL_SESG(E24, RMII4TXD0, RMII4, SIG_DESC_SET(SCU4B0, 30), + SIG_DESC_CLEAR(SCU510, 1)); +-PIN_DECL_3(E24, GPIOD6, NDSR3, RGMII4TXD0, RMII4TXD0); ++SIG_EXPR_LIST_DECL_SESG(E24, VPA_G5, VPA, SIG_DESC_CLEAR(SCU410, 30), ++ SIG_DESC_CLEAR(SCU4B0, 30)); ++PIN_DECL_4(E24, GPIOD6, NDSR3, RGMII4TXD0, RMII4TXD0, VPA_G5); + FUNC_GROUP_DECL(NDSR3, E24); + + #define E25 31 +@@ -286,73 +310,99 @@ + SIG_DESC_SET(SCU510, 1)); + SIG_EXPR_LIST_DECL_SESG(E25, RMII4TXD1, RMII4, SIG_DESC_SET(SCU4B0, 31), + SIG_DESC_CLEAR(SCU510, 1)); +-PIN_DECL_3(E25, GPIOD7, NRI3, RGMII4TXD1, RMII4TXD1); ++SIG_EXPR_LIST_DECL_SESG(E25, VPA_G6, VPA, SIG_DESC_CLEAR(SCU410, 31), ++ SIG_DESC_CLEAR(SCU4B0, 31)); ++PIN_DECL_4(E25, GPIOD7, NRI3, RGMII4TXD1, RMII4TXD1, VPA_G6); + FUNC_GROUP_DECL(NRI3, E25); + + #define D26 32 +-SIG_EXPR_LIST_DECL_SESG(D26, NDTR3, NDTR3, SIG_DESC_SET(SCU414, 0)); ++SIG_EXPR_LIST_DECL_SESG(D26, NDTR3, NDTR3, SIG_DESC_SET(SCU414, 0), ++ SIG_DESC_CLEAR(SCU470, 16)); + SIG_EXPR_LIST_DECL_SESG(D26, RGMII4TXD2, RGMII4, SIG_DESC_SET(SCU4B4, 0), +- SIG_DESC_SET(SCU510, 1)); +-PIN_DECL_2(D26, GPIOE0, NDTR3, RGMII4TXD2); ++ SIG_DESC_CLEAR(SCU470, 16), SIG_DESC_SET(SCU510, 1)); ++SIG_EXPR_LIST_DECL_SESG(D26, VPA_G7, VPA, SIG_DESC_CLEAR(SCU414, 0), ++ SIG_DESC_CLEAR(SCU4B4, 0)); ++PIN_DECL_3(D26, GPIOE0, NDTR3, RGMII4TXD2, VPA_G7); + FUNC_GROUP_DECL(NDTR3, D26); + + #define D24 33 +-SIG_EXPR_LIST_DECL_SESG(D24, NRTS3, NRTS3, SIG_DESC_SET(SCU414, 1)); ++SIG_EXPR_LIST_DECL_SESG(D24, NRTS3, NRTS3, SIG_DESC_SET(SCU414, 1), ++ SIG_DESC_CLEAR(SCU470, 17)); + SIG_EXPR_LIST_DECL_SESG(D24, RGMII4TXD3, RGMII4, SIG_DESC_SET(SCU4B4, 1), +- SIG_DESC_SET(SCU510, 1)); +-PIN_DECL_2(D24, GPIOE1, NRTS3, RGMII4TXD3); ++ SIG_DESC_CLEAR(SCU470, 17), SIG_DESC_SET(SCU510, 1)); ++SIG_EXPR_LIST_DECL_SESG(D24, VPA_R0, VPA, SIG_DESC_CLEAR(SCU414, 1), ++ SIG_DESC_CLEAR(SCU4B4, 1)); ++PIN_DECL_3(D24, GPIOE1, NRTS3, RGMII4TXD3, VPA_R0); + FUNC_GROUP_DECL(NRTS3, D24); + + #define C25 34 +-SIG_EXPR_LIST_DECL_SESG(C25, NCTS4, NCTS4, SIG_DESC_SET(SCU414, 2)); ++SIG_EXPR_LIST_DECL_SESG(C25, NCTS4, NCTS4, SIG_DESC_SET(SCU414, 2), ++ SIG_DESC_CLEAR(SCU470, 18)); + SIG_EXPR_LIST_DECL_SESG(C25, RGMII4RXCK, RGMII4, SIG_DESC_SET(SCU4B4, 2), +- SIG_DESC_SET(SCU510, 1)); ++ SIG_DESC_CLEAR(SCU470, 18), SIG_DESC_SET(SCU510, 1)); + SIG_EXPR_LIST_DECL_SESG(C25, RMII4RCLKI, RMII4, SIG_DESC_SET(SCU4B4, 2), +- SIG_DESC_CLEAR(SCU510, 1)); +-PIN_DECL_3(C25, GPIOE2, NCTS4, RGMII4RXCK, RMII4RCLKI); ++ SIG_DESC_CLEAR(SCU470, 18), SIG_DESC_CLEAR(SCU510, 1)); ++SIG_EXPR_LIST_DECL_SESG(C25, VPA_R1, VPA, SIG_DESC_CLEAR(SCU414, 2), ++ SIG_DESC_CLEAR(SCU4B4, 2)); ++PIN_DECL_4(C25, GPIOE2, NCTS4, RGMII4RXCK, RMII4RCLKI, VPA_R1); + FUNC_GROUP_DECL(NCTS4, C25); + + #define C26 35 +-SIG_EXPR_LIST_DECL_SESG(C26, NDCD4, NDCD4, SIG_DESC_SET(SCU414, 3)); ++SIG_EXPR_LIST_DECL_SESG(C26, NDCD4, NDCD4, SIG_DESC_SET(SCU414, 3), ++ SIG_DESC_CLEAR(SCU470, 19)); + SIG_EXPR_LIST_DECL_SESG(C26, RGMII4RXCTL, RGMII4, SIG_DESC_SET(SCU4B4, 3), +- SIG_DESC_SET(SCU510, 1)); +-PIN_DECL_2(C26, GPIOE3, NDCD4, RGMII4RXCTL); ++ SIG_DESC_CLEAR(SCU470, 19), SIG_DESC_SET(SCU510, 1)); ++SIG_EXPR_LIST_DECL_SESG(C26, VPA_R2, VPA, SIG_DESC_CLEAR(SCU414, 3), ++ SIG_DESC_CLEAR(SCU4B4, 3)); ++PIN_DECL_3(C26, GPIOE3, NDCD4, RGMII4RXCTL, VPA_R2); + FUNC_GROUP_DECL(NDCD4, C26); + + #define C24 36 +-SIG_EXPR_LIST_DECL_SESG(C24, NDSR4, NDSR4, SIG_DESC_SET(SCU414, 4)); ++SIG_EXPR_LIST_DECL_SESG(C24, NDSR4, NDSR4, SIG_DESC_SET(SCU414, 4), ++ SIG_DESC_CLEAR(SCU470, 20)); + SIG_EXPR_LIST_DECL_SESG(C24, RGMII4RXD0, RGMII4, SIG_DESC_SET(SCU4B4, 4), +- SIG_DESC_SET(SCU510, 1)); ++ SIG_DESC_CLEAR(SCU470, 20), SIG_DESC_SET(SCU510, 1)); + SIG_EXPR_LIST_DECL_SESG(C24, RMII4RXD0, RMII4, SIG_DESC_SET(SCU4B4, 4), +- SIG_DESC_CLEAR(SCU510, 1)); +-PIN_DECL_3(C24, GPIOE4, NDSR4, RGMII4RXD0, RMII4RXD0); ++ SIG_DESC_CLEAR(SCU470, 20), SIG_DESC_CLEAR(SCU510, 1)); ++SIG_EXPR_LIST_DECL_SESG(C24, VPA_R3, VPA, SIG_DESC_CLEAR(SCU414, 4), ++ SIG_DESC_CLEAR(SCU4B4, 4)); ++PIN_DECL_4(C24, GPIOE4, NDSR4, RGMII4RXD0, RMII4RXD0, VPA_R3); + FUNC_GROUP_DECL(NDSR4, C24); + + #define B26 37 +-SIG_EXPR_LIST_DECL_SESG(B26, NRI4, NRI4, SIG_DESC_SET(SCU414, 5)); ++SIG_EXPR_LIST_DECL_SESG(B26, NRI4, NRI4, SIG_DESC_SET(SCU414, 5), ++ SIG_DESC_CLEAR(SCU470, 21)); + SIG_EXPR_LIST_DECL_SESG(B26, RGMII4RXD1, RGMII4, SIG_DESC_SET(SCU4B4, 5), +- SIG_DESC_SET(SCU510, 1)); ++ SIG_DESC_CLEAR(SCU470, 21), SIG_DESC_SET(SCU510, 1)); + SIG_EXPR_LIST_DECL_SESG(B26, RMII4RXD1, RMII4, SIG_DESC_SET(SCU4B4, 5), +- SIG_DESC_CLEAR(SCU510, 1)); +-PIN_DECL_3(B26, GPIOE5, NRI4, RGMII4RXD1, RMII4RXD1); ++ SIG_DESC_CLEAR(SCU470, 21), SIG_DESC_CLEAR(SCU510, 1)); ++SIG_EXPR_LIST_DECL_SESG(B26, VPA_R4, VPA, SIG_DESC_CLEAR(SCU414, 5), ++ SIG_DESC_CLEAR(SCU4B4, 5)); ++PIN_DECL_4(B26, GPIOE5, NRI4, RGMII4RXD1, RMII4RXD1, VPA_R4); + FUNC_GROUP_DECL(NRI4, B26); + + #define B25 38 +-SIG_EXPR_LIST_DECL_SESG(B25, NDTR4, NDTR4, SIG_DESC_SET(SCU414, 6)); ++SIG_EXPR_LIST_DECL_SESG(B25, NDTR4, NDTR4, SIG_DESC_SET(SCU414, 6), ++ SIG_DESC_CLEAR(SCU470, 22)); + SIG_EXPR_LIST_DECL_SESG(B25, RGMII4RXD2, RGMII4, SIG_DESC_SET(SCU4B4, 6), +- SIG_DESC_SET(SCU510, 1)); ++ SIG_DESC_CLEAR(SCU470, 22), SIG_DESC_SET(SCU510, 1)); + SIG_EXPR_LIST_DECL_SESG(B25, RMII4CRSDV, RMII4, SIG_DESC_SET(SCU4B4, 6), +- SIG_DESC_CLEAR(SCU510, 1)); +-PIN_DECL_3(B25, GPIOE6, NDTR4, RGMII4RXD2, RMII4CRSDV); ++ SIG_DESC_CLEAR(SCU470, 22), SIG_DESC_CLEAR(SCU510, 1)); ++SIG_EXPR_LIST_DECL_SESG(B25, VPA_R5, VPA, SIG_DESC_CLEAR(SCU414, 6), ++ SIG_DESC_CLEAR(SCU4B4, 6)); ++PIN_DECL_4(B25, GPIOE6, NDTR4, RGMII4RXD2, RMII4CRSDV, VPA_R5); + FUNC_GROUP_DECL(NDTR4, B25); + + #define B24 39 +-SIG_EXPR_LIST_DECL_SESG(B24, NRTS4, NRTS4, SIG_DESC_SET(SCU414, 7)); ++SIG_EXPR_LIST_DECL_SESG(B24, NRTS4, NRTS4, SIG_DESC_SET(SCU414, 7), ++ SIG_DESC_CLEAR(SCU470, 23)); + SIG_EXPR_LIST_DECL_SESG(B24, RGMII4RXD3, RGMII4, SIG_DESC_SET(SCU4B4, 7), +- SIG_DESC_SET(SCU510, 1)); ++ SIG_DESC_CLEAR(SCU470, 23), SIG_DESC_SET(SCU510, 1)); + SIG_EXPR_LIST_DECL_SESG(B24, RMII4RXER, RMII4, SIG_DESC_SET(SCU4B4, 7), +- SIG_DESC_CLEAR(SCU510, 1)); +-PIN_DECL_3(B24, GPIOE7, NRTS4, RGMII4RXD3, RMII4RXER); ++ SIG_DESC_CLEAR(SCU470, 23), SIG_DESC_CLEAR(SCU510, 1)); ++SIG_EXPR_LIST_DECL_SESG(B24, VPA_R6, VPA, SIG_DESC_CLEAR(SCU414, 7), ++ SIG_DESC_CLEAR(SCU4B4, 7)); ++PIN_DECL_4(B24, GPIOE7, NRTS4, RGMII4RXD3, RMII4RXER, VPA_R6); + FUNC_GROUP_DECL(NRTS4, B24); + + FUNC_GROUP_DECL(RGMII4, F24, E23, E24, E25, D26, D24, C25, C26, C24, B26, B25, +@@ -364,27 +414,39 @@ + #define D22 40 + SIG_EXPR_LIST_DECL_SESG(D22, SD1CLK, SD1, SIG_DESC_SET(SCU414, 8)); + SIG_EXPR_LIST_DECL_SEMG(D22, PWM8, PWM8G0, PWM8, SIG_DESC_SET(SCU4B4, 8)); +-PIN_DECL_2(D22, GPIOF0, SD1CLK, PWM8); ++SIG_EXPR_LIST_DECL_SESG(D22, VPA_R7, VPA, SIG_DESC_CLEAR(SCU414, 8), ++ SIG_DESC_CLEAR(SCU4B4, 8)); ++PIN_DECL_3(D22, GPIOF0, SD1CLK, PWM8, VPA_R7); + GROUP_DECL(PWM8G0, D22); + + #define E22 41 + SIG_EXPR_LIST_DECL_SESG(E22, SD1CMD, SD1, SIG_DESC_SET(SCU414, 9)); + SIG_EXPR_LIST_DECL_SEMG(E22, PWM9, PWM9G0, PWM9, SIG_DESC_SET(SCU4B4, 9)); +-PIN_DECL_2(E22, GPIOF1, SD1CMD, PWM9); ++SIG_EXPR_LIST_DECL_SESG(E22, VPAHS, VPA, SIG_DESC_CLEAR(SCU414, 9), ++ SIG_DESC_CLEAR(SCU4B4, 9)); ++PIN_DECL_3(E22, GPIOF1, SD1CMD, PWM9, VPAHS); + GROUP_DECL(PWM9G0, E22); + + #define D23 42 + SIG_EXPR_LIST_DECL_SESG(D23, SD1DAT0, SD1, SIG_DESC_SET(SCU414, 10)); + SIG_EXPR_LIST_DECL_SEMG(D23, PWM10, PWM10G0, PWM10, SIG_DESC_SET(SCU4B4, 10)); +-PIN_DECL_2(D23, GPIOF2, SD1DAT0, PWM10); ++SIG_EXPR_LIST_DECL_SESG(D23, VPAVS, VPA, SIG_DESC_CLEAR(SCU414, 10), ++ SIG_DESC_CLEAR(SCU4B4, 10)); ++PIN_DECL_3(D23, GPIOF2, SD1DAT0, PWM10, VPAVS); + GROUP_DECL(PWM10G0, D23); + + #define C23 43 + SIG_EXPR_LIST_DECL_SESG(C23, SD1DAT1, SD1, SIG_DESC_SET(SCU414, 11)); + SIG_EXPR_LIST_DECL_SEMG(C23, PWM11, PWM11G0, PWM11, SIG_DESC_SET(SCU4B4, 11)); +-PIN_DECL_2(C23, GPIOF3, SD1DAT1, PWM11); ++SIG_EXPR_LIST_DECL_SESG(C23, VPADE, VPA, SIG_DESC_CLEAR(SCU414, 11), ++ SIG_DESC_CLEAR(SCU4B4, 11)); ++PIN_DECL_3(C23, GPIOF3, SD1DAT1, PWM11, VPADE); + GROUP_DECL(PWM11G0, C23); + ++FUNC_GROUP_DECL(VPA, H24, J22, H22, H23, G22, F22, G23, G24, F23, F26, F25, ++ E26, F24, E23, E24, E25, D26, D24, C25, C26, C24, B26, B25, ++ B24, D22, E22, D23, C23); + -+ return 0; -+} -+ -+static int aspeed_can_exit_reset_mode(struct net_device *ndev) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ unsigned long timeout; -+ -+ aspeed_can_clr_bit(priv, CAN_CTRL, CAN_CTRL_RST_BIT); -+ -+ timeout = jiffies + (1 * HZ); -+ while (aspeed_can_check_reset_mode(ndev)) { -+ if (time_after(jiffies, timeout)) { -+ netdev_warn(ndev, "timed out for config mode\n"); -+ return -ETIMEDOUT; -+ } -+ -+ usleep_range(500, 10000); -+ } -+ -+ return 0; -+} -+ -+static void aspeed_can_err_init(struct net_device *ndev) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ u32 reg_val; -+ -+ reg_val = (STAT_AFWL << CAN_ERR_AFWL_BITOFF) & CAN_ERR_AFWL_MASK; -+ reg_val |= (STAT_EWL << CAN_ERR_EWL_BITOFF) & CAN_ERR_EWL_MASK; -+ -+ writel(reg_val, priv->reg_base + CAN_ERR_STAT); -+} -+ -+static void aspeed_can_interrupt_conf(struct net_device *ndev) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ u32 inte; -+ -+ inte = CAN_INT_EIE_BIT | CAN_INT_TSIE_BIT | CAN_INT_TPIE_BIT | -+ CAN_INT_RAFIE_BIT | CAN_INT_RFIE_BIT | CAN_INT_ROIE_BIT | -+ CAN_INT_RIE_BIT | CAN_INT_BEIE_BIT | CAN_INT_ALIE_BIT | -+ CAN_INT_EPIE_BIT; -+ -+ writel(inte, priv->reg_base + CAN_INTE); -+} -+ -+static void aspeed_can_tb_mode_conf(struct net_device *ndev) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ -+ if (priv->tb_mode == STB_MODE) -+ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_TBSEL_BIT); -+ else -+ aspeed_can_clr_bit(priv, CAN_CTRL, CAN_CTRL_TBSEL_BIT); -+} -+ -+static void aspeed_can_sack_conf(struct net_device *ndev, bool enable) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ -+ if (enable) -+ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_SACK_BIT); -+ else -+ aspeed_can_clr_bit(priv, CAN_CTRL, CAN_CTRL_SACK_BIT); -+} -+ -+static void aspeed_can_loopback_ext_conf(struct net_device *ndev, bool enable) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ -+ if (enable) -+ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_LBMEMOD_BIT); -+ else -+ aspeed_can_clr_bit(priv, CAN_CTRL, CAN_CTRL_LBMEMOD_BIT); -+} -+ -+static void aspeed_can_loopback_int_conf(struct net_device *ndev, bool enable) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ -+ if (enable) -+ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_LBMIMOD_BIT); -+ else -+ aspeed_can_clr_bit(priv, CAN_CTRL, CAN_CTRL_LBMIMOD_BIT); -+} -+ -+static void aspeed_can_fd_init(struct net_device *ndev) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ -+ aspeed_can_set_bit(priv, CAN_MODE_CONFIG, BIT(0)); -+} -+ -+static void aspeed_can_reg_dump(struct net_device *ndev) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ u32 reg_val; -+ u32 i; -+ -+ reg_val = readl(priv->reg_base + CAN_AC_SEG); -+ netdev_info(ndev, "(REG004) CAN_AC_SEG = 0x%08x\n", reg_val); -+ netdev_info(ndev, " ac_seg1 (8:0): 0x%02x\n", -+ (u32)((reg_val & CAN_TIMING_AC_SEG1_MASK) >> -+ CAN_TIMING_AC_SEG1_BITOFF)); -+ netdev_info(ndev, " ac_seg2(22:16): 0x%02x\n", -+ (u32)((reg_val & CAN_TIMING_AC_SEG2_MASK) >> -+ CAN_TIMING_AC_SEG2_BITOFF)); -+ netdev_info(ndev, " ac_sjw (30:24): 0x%02x\n", -+ (u32)((reg_val & CAN_TIMING_AC_SJW_MASK) >> -+ CAN_TIMING_AC_SJW_BITOFF)); -+ -+ reg_val = readl(priv->reg_base + CAN_FD_SEG); -+ netdev_info(ndev, "(REG008) CAN_FD_SEG = 0x%08x\n", reg_val); -+ netdev_info(ndev, " fd_seg1 (7:0): 0x%02x\n", -+ (u32)((reg_val & CAN_TIMING_FD_SEG1_MASK) >> -+ CAN_TIMING_FD_SEG1_BITOFF)); -+ netdev_info(ndev, " fd_seg2(22:16): 0x%02x\n", -+ (u32)((reg_val & CAN_TIMING_FD_SEG2_MASK) >> -+ CAN_TIMING_FD_SEG2_BITOFF)); -+ netdev_info(ndev, " fd_sjw (30:24): 0x%02x\n", -+ (u32)((reg_val & CAN_TIMING_FD_SJW_MASK) >> -+ CAN_TIMING_FD_SJW_BITOFF)); -+ -+ reg_val = readl(priv->reg_base + CAN_BITITME); -+ netdev_info(ndev, "(REG010) CAN_BITITME = 0x%08x\n", reg_val); -+ netdev_info(ndev, " prescaler (4:0): 0x%02x\n", -+ (u32)((reg_val & CAN_TIMING_PRESC_MASK) >> -+ CAN_TIMING_PRESC_BITOFF)); -+ netdev_info(ndev, " fd_sspoff(15:8): 0x%02x\n", -+ (u32)((reg_val & CAN_TIMING_FD_SSPOFF_MASK) >> -+ CAN_TIMING_FD_SSPOFF_BITOFF)); -+ -+ reg_val = readl(priv->reg_base + CAN_INTF); -+ netdev_info(ndev, "(REG014) CAN_INTF = 0x%08x\n", reg_val); -+ netdev_info(ndev, " EIF (1): %d\n", (reg_val & CAN_INT_EIF_BIT) ? 1 : 0); -+ netdev_info(ndev, " TSIF (2): %d\n", (reg_val & CAN_INT_TSIF_BIT) ? 1 : 0); -+ netdev_info(ndev, " TPIF (3): %d\n", (reg_val & CAN_INT_TPIF_BIT) ? 1 : 0); -+ netdev_info(ndev, " RAFIF (4): %d\n", (reg_val & CAN_INT_RAFIF_BIT) ? 1 : 0); -+ netdev_info(ndev, " RFIF (5): %d\n", (reg_val & CAN_INT_RFIF_BIT) ? 1 : 0); -+ netdev_info(ndev, " ROIF (6): %d\n", (reg_val & CAN_INT_ROIF_BIT) ? 1 : 0); -+ netdev_info(ndev, " RIF (7): %d\n", (reg_val & CAN_INT_RIF_BIT) ? 1 : 0); -+ netdev_info(ndev, " BEIF (8): %d\n", (reg_val & CAN_INT_BEIF_BIT) ? 1 : 0); -+ netdev_info(ndev, " EPIF (10): %d\n", (reg_val & CAN_INT_EPIF_BIT) ? 1 : 0); -+ netdev_info(ndev, " EPASS(30): %d\n", (reg_val & CAN_EPASS_BIT) ? 1 : 0); -+ netdev_info(ndev, " EWARN(31): %d\n", (reg_val & CAN_INT_EWARN_BIT) ? 1 : 0); -+ -+ reg_val = readl(priv->reg_base + CAN_INTE); -+ netdev_info(ndev, "(REG018) CAN_INTE = 0x%08x\n", reg_val); -+ netdev_info(ndev, " EIE (1): %d\n", (reg_val & CAN_INT_EIE_BIT) ? 1 : 0); -+ netdev_info(ndev, " TSIE (2): %d\n", (reg_val & CAN_INT_TSIE_BIT) ? 1 : 0); -+ netdev_info(ndev, " TPIE (3): %d\n", (reg_val & CAN_INT_TPIE_BIT) ? 1 : 0); -+ netdev_info(ndev, " RAFIE (4): %d\n", (reg_val & CAN_INT_RAFIE_BIT) ? 1 : 0); -+ netdev_info(ndev, " RFIE (5): %d\n", (reg_val & CAN_INT_RFIE_BIT) ? 1 : 0); -+ netdev_info(ndev, " ROIE (6): %d\n", (reg_val & CAN_INT_ROIE_BIT) ? 1 : 0); -+ netdev_info(ndev, " RIE (7): %d\n", (reg_val & CAN_INT_RIE_BIT) ? 1 : 0); -+ netdev_info(ndev, " BEIE (8): %d\n", (reg_val & CAN_INT_BEIE_BIT) ? 1 : 0); -+ netdev_info(ndev, " EPIE (10): %d\n", (reg_val & CAN_INT_EPIE_BIT) ? 1 : 0); -+ -+ reg_val = readl(priv->reg_base + CAN_TSTAT); -+ netdev_info(ndev, "(REG01C) CAN_TSTAT = 0x%08x\n", reg_val); -+ netdev_info(ndev, " TSTAT1 (10:8): 0x%02x\n", -+ (u32)((reg_val & CAN_TSTAT1_MASK) >> CAN_TSTAT1_BITOFF)); -+ netdev_info(ndev, " TSTAT2(26:24): 0x%02x\n", -+ (u32)((reg_val & CAN_TSTAT2_MASK) >> CAN_TSTAT2_BITOFF)); -+ netdev_info(ndev, " 000 : no tx\n"); -+ netdev_info(ndev, " 001 : on-going\n"); -+ netdev_info(ndev, " 010 : lost arbitration\n"); -+ netdev_info(ndev, " 011 : transmitted\n"); -+ netdev_info(ndev, " 100 : aborted\n"); -+ netdev_info(ndev, " 101 : disturbed\n"); -+ netdev_info(ndev, " 110 : reject\n"); -+ -+ reg_val = readl(priv->reg_base + CAN_CTRL); -+ netdev_info(ndev, "(REG028) CAN_CTRL = 0x%08x\n", reg_val); -+ netdev_info(ndev, " BUSOFF (0): %d\n", (reg_val & CAN_CTRL_BUSOFF_BIT) ? 1 : 0); -+ netdev_info(ndev, " LBMIMOD (5): %d\n", (reg_val & CAN_CTRL_LBMIMOD_BIT) ? 1 : 0); -+ netdev_info(ndev, " LBMEMOD (6): %d\n", (reg_val & CAN_CTRL_LBMEMOD_BIT) ? 1 : 0); -+ netdev_info(ndev, " RST (7): %d\n", (reg_val & CAN_CTRL_RST_BIT) ? 1 : 0); -+ netdev_info(ndev, " TPE (12): %d\n", (reg_val & CAN_CTRL_TPE_BIT) ? 1 : 0); -+ netdev_info(ndev, " STBY (13): %d\n", (reg_val & CAN_CTRL_STBY_BIT) ? 1 : 0); -+ netdev_info(ndev, " TBSEL (15): %d\n", (reg_val & CAN_CTRL_TBSEL_BIT) ? 1 : 0); -+ netdev_info(ndev, " TTBM (20): %d\n", (reg_val & CAN_CTRL_TTBM_BIT) ? 1 : 0); -+ netdev_info(ndev, " TSMODE (21): %d\n", (reg_val & CAN_CTRL_TSMODE_BIT) ? 1 : 0); -+ netdev_info(ndev, " TSNEXT (22): %d\n", (reg_val & CAN_CTRL_TSNEXT_BIT) ? 1 : 0); -+ netdev_info(ndev, " RSTAT (25:24): 0x%02x\n", -+ (u32)((reg_val & CAN_CTRL_RSTAT_NOT_EMPTY_MASKT) >> 24)); -+ netdev_info(ndev, " RREL (28): %d\n", (reg_val & CAN_CTRL_RREL_BIT) ? 1 : 0); -+ -+ reg_val = readl(priv->reg_base + CAN_ERR_STAT); -+ netdev_info(ndev, "(REG02C) ERR_STAT = 0x%08x\n", reg_val); -+ netdev_info(ndev, " EWL (3:0): 0x%02x\n", -+ (u32)((reg_val & CAN_ERR_EWL_MASK) >> CAN_ERR_EWL_BITOFF)); -+ netdev_info(ndev, " AFWL (7:4): 0x%02x\n", -+ (u32)((reg_val & CAN_ERR_AFWL_MASK) >> CAN_ERR_AFWL_BITOFF)); -+ netdev_info(ndev, " ALC (12:8): 0x%02x\n", -+ (u32)((reg_val & CAN_ERR_ALC_MASK) >> CAN_ERR_ALC_BITOFF)); -+ netdev_info(ndev, " KOER (15:13): 0x%02x\n", -+ (u32)((reg_val & CAN_ERR_KOER_MASK) >> CAN_ERR_KOER_BITOFF)); -+ netdev_info(ndev, " 000 : no error\n"); -+ netdev_info(ndev, " 001 : bit error\n"); -+ netdev_info(ndev, " 010 : form error\n"); -+ netdev_info(ndev, " 011 : stuff error\n"); -+ netdev_info(ndev, " 100 : ack error\n"); -+ netdev_info(ndev, " 101 : crc error\n"); -+ netdev_info(ndev, " 110 : other error\n"); -+ netdev_info(ndev, " RECNT (23:16): 0x%02x\n", -+ (u32)((reg_val & CAN_ERR_RECNT_MASK) >> CAN_ERR_RECNT_BITOFF)); -+ netdev_info(ndev, " TECNT (31:24): 0x%02x\n", -+ (u32)((reg_val & CAN_ERR_TECNT_MASK) >> CAN_ERR_TECNT_BITOFF)); -+ -+ for (i = 0; i < 0x50; i += 4) -+ netdev_info(ndev, "REG(%03x): 0x%08x\n", i, readl(priv->reg_base + i)); -+} -+ -+static int aspeed_can_set_bittiming(struct net_device *ndev) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ struct can_bittiming *bt = &priv->can.bittiming; -+ struct can_bittiming *dbt = &priv->can.data_bittiming; -+ u32 btr0, btr1; -+ u32 can_fd_ssp; -+ -+ /* check whether the CAN controller is in reset mode */ -+ if (!aspeed_can_check_reset_mode(ndev)) { -+ netdev_alert(ndev, -+ "BUG! Cannot set bittiming - not in reset mode\n"); -+ return -EPERM; -+ } -+ -+ /* parameter sanity */ -+ if (bt->brp < 1 || bt->prop_seg + bt->phase_seg1 < 1 || -+ bt->phase_seg2 < 1 || bt->sjw < 1) { -+ netdev_alert(ndev, -+ "invalid bittiming parameters\n"); -+ netdev_alert(ndev, -+ "brp: %x, prop: %x, seg1: %x, seg2: %x, sjw: %x\n", -+ bt->brp, bt->prop_seg, bt->phase_seg1, -+ bt->phase_seg2, bt->sjw); -+ return -EPERM; -+ } -+ -+ /* setting prescaler value in PRESC Register */ -+ btr0 = (bt->brp - 1); -+ -+ /* setting time segment 1 in SEG_1 Register */ -+ btr1 = (1 + bt->prop_seg + bt->phase_seg1 - 2); -+ -+ /* Setting Time Segment 2 in SEG_2 Register */ -+ btr1 |= (bt->phase_seg2 - 1) << 16; -+ -+ /* Setting Synchronous jump width in BTR Register */ -+ btr1 |= (bt->sjw - 1) << 24; -+ -+ writel(btr1, priv->reg_base + CAN_AC_SEG); -+ -+ if (dbt->prop_seg != 0 && dbt->phase_seg1 != 0 && -+ dbt->phase_seg2 != 0) { -+ if (bt->brp != dbt->brp) { -+ netdev_alert(ndev, -+ "nominal (%d) and data (%d) prescaler isn't the same\n", -+ bt->brp, dbt->brp); -+ return -EPERM; -+ } -+ -+ if (dbt->sjw < 1) { -+ netdev_alert(ndev, -+ "invalid data sjw %x\n", dbt->sjw); -+ return -EPERM; -+ } -+ -+ /* Setting Time Segment 1 in BTR Register */ -+ btr1 = 1 + dbt->prop_seg + dbt->phase_seg1 - 2; -+ -+ /* Setting Time Segment 2 in BTR Register */ -+ btr1 |= (dbt->phase_seg2 - 1) << 16; -+ -+ /* Setting Synchronous jump width in BTR Register */ -+ btr1 |= (dbt->sjw - 1) << 24; -+ -+ writel(btr1, priv->reg_base + CAN_FD_SEG); -+ -+ /* seg_1 + 1 */ -+ can_fd_ssp = 1 + dbt->prop_seg + dbt->phase_seg1 + 1; -+ -+ btr0 |= can_fd_ssp << 8; -+ } -+ -+ writel(btr0 | 0x10000000, priv->reg_base + CAN_BITITME); -+ -+ return 0; -+} -+ -+static int aspeed_can_chip_start(struct net_device *ndev) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ int err; -+ -+ /* Check if it is in reset mode */ -+ err = aspeed_can_set_reset_mode(ndev); -+ if (err < 0) -+ return err; -+ -+ err = aspeed_can_set_bittiming(ndev); -+ if (err < 0) -+ return err; -+ -+ /* Always config to FD mode since it is -+ * backward compatibility with CAN2.0B. -+ */ -+ aspeed_can_fd_init(ndev); -+ -+ err = aspeed_can_exit_reset_mode(ndev); -+ if (err < 0) -+ return err; -+ -+ aspeed_can_err_init(ndev); -+ aspeed_can_interrupt_conf(ndev); -+ -+ aspeed_can_tb_mode_conf(ndev); -+ -+ aspeed_can_loopback_ext_conf(ndev, false); -+ if (priv->flag & ASPEED_CAN_INTERNEL_LOOPBACK) { -+ aspeed_can_loopback_int_conf(ndev, true); -+ aspeed_can_sack_conf(ndev, true); -+ } else { -+ if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) { -+ aspeed_can_loopback_ext_conf(ndev, true); -+ aspeed_can_sack_conf(ndev, true); -+ } -+ aspeed_can_loopback_int_conf(ndev, false); -+ } -+ -+ priv->can.state = CAN_STATE_ERROR_ACTIVE; -+ priv->frame_handle = 0; -+ -+ return 0; -+} -+ -+static int aspeed_can_do_set_mode(struct net_device *ndev, enum can_mode mode) -+{ -+ int ret; -+ -+ switch (mode) { -+ case CAN_MODE_START: -+ ret = aspeed_can_chip_start(ndev); -+ if (ret < 0) { -+ netdev_err(ndev, "aspeed_can_chip_start failed!\n"); -+ return ret; -+ } -+ netif_wake_queue(ndev); -+ break; -+ default: -+ netdev_err(ndev, "unexpect can mode: %d\n", (u32)mode); -+ ret = -EOPNOTSUPP; -+ break; -+ } -+ -+ return ret; -+} -+ -+static void aspeed_can_write_frame(struct net_device *ndev, -+ struct sk_buff *skb) -+{ -+ u32 id; -+ struct canfd_frame *cf = (struct canfd_frame *)skb->data; -+ u32 i; -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ u32 buf_ctrl = 0; -+ u32 can_ctrl; -+ u32 can_type; -+ -+ can_ctrl = readl(priv->reg_base + CAN_CTRL); -+ -+ /* Watch carefully on the bit sequence */ -+ if (cf->can_id & CAN_EFF_FLAG) { -+ id = (cf->can_id & CAN_EFF_MASK) << CAN_BUF_ID_EFF_BITOFF; -+ buf_ctrl |= CAN_BUF_IDE_BIT; -+ } else { -+ /* Standard CAN ID format */ -+ id = (cf->can_id & CAN_SFF_MASK) << CAN_BUF_ID_BFF_BITOFF; -+ } -+ -+ if (cf->can_id & CAN_RTR_FLAG) -+ buf_ctrl |= CAN_BUF_RMF_BIT; -+ -+ buf_ctrl |= can_fd_len2dlc(cf->len); -+ -+ if (can_is_canfd_skb(skb)) { -+ buf_ctrl |= CAN_BUF_FDF_BIT; -+ if (cf->flags & CANFD_BRS) -+ buf_ctrl |= CAN_BUF_BRS_BIT; -+ } -+ -+ can_type = priv->frame_handle << CAN_BUF_HANDLE_BITOFF; -+ -+ writel(id, priv->reg_base + CAN_TBUF_ID); -+ writel(buf_ctrl, priv->reg_base + CAN_TBUF_CTL); -+ writel(can_type, priv->reg_base + CAN_TBUF_TYPE); -+ -+ writel(0x0, priv->reg_base + CAN_TBUF_TYPE); -+ writel(0x0, priv->reg_base + CAN_TBUF_ACF); -+ -+ if (cf->can_id & CAN_RTR_FLAG) -+ return; -+ -+ for (i = 0; i < (cf->len / 4 + 3) * 4; i += 4) { -+ writel(*(u32 *)(cf->data + i), -+ priv->reg_base + CAN_TBUF_DATA + i); -+ } -+} -+ -+static int aspeed_can_start_frame_xmit(struct sk_buff *skb, -+ struct net_device *ndev) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ u32 i = 0; -+ u32 can_ctrl; -+ u32 int_flag; -+ u32 skb_idx; -+ int ret; -+ -+ /* avoid transmitting data finish suddenly */ -+ while (i < 3) { -+ can_ctrl = readl(priv->reg_base + CAN_CTRL); -+ int_flag = readl(priv->reg_base + CAN_INTF); -+ i++; -+ } -+ -+ /* check whether STB or PTB is full */ -+ if ((can_ctrl & CAN_CTRL_TBSEL_BIT) && -+ (can_ctrl & CAN_CTRL_TSFF_BIT)) -+ return -ENOSPC; -+ -+ if (!(can_ctrl & CAN_CTRL_TBSEL_BIT) && -+ ((can_ctrl & CAN_CTRL_TPE_BIT) || -+ (int_flag & CAN_INT_TPIF_BIT))) -+ return -ENOSPC; -+ -+ if (priv->frame_handle == 0x100) -+ priv->frame_handle = 0; -+ -+ /* Use skb idex to check whether -+ * the same handle already in STB. -+ */ -+ skb_idx = aspeed_can_get_skb_idx(ndev, priv->frame_handle); -+ if (skb_idx != STB_INVALID_SKB_IDX) { -+ netdev_err(ndev, "repeat handle %d\n", priv->frame_handle); -+ return -ENOSPC; -+ } -+ -+ aspeed_can_write_frame(ndev, skb); -+ -+ if (can_ctrl & CAN_CTRL_TBSEL_BIT) { -+ /* STB */ -+ ret = can_put_echo_skb(skb, ndev, priv->head_ptr->skb_idx, 0); -+ if (ret) { -+ netdev_err(ndev, "fail to put skb for stb %d\n", ret); -+ return ret; -+ } -+ -+ priv->head_ptr->handle = priv->frame_handle; -+ priv->head_ptr = priv->head_ptr->next; -+ -+ /* STB is full */ -+ if (priv->head_ptr == priv->tail_ptr) -+ netif_stop_queue(ndev); -+ -+ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_TSNEXT_BIT); -+ -+ /* no frame is transmitting or there is no unhandled finish flag */ -+ if ((priv->stb_mode_policy & STB_TX_MODE_ONE) && -+ !(can_ctrl & CAN_CTRL_TSONE_BIT) && -+ !(int_flag & CAN_INT_TSIF_BIT)) -+ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_TSONE_BIT); -+ else if ((priv->stb_mode_policy & STB_TX_MODE_ALL) && -+ !(can_ctrl & CAN_CTRL_TSALL_BIT) && -+ !(int_flag & CAN_INT_TSIF_BIT)) -+ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_TSALL_BIT); -+ } else { -+ /* PTB */ -+ ret = can_put_echo_skb(skb, ndev, 0, 0); -+ if (ret) { -+ netdev_err(ndev, "fail to put skb for ptb %d\n", ret); -+ return ret; -+ } -+ -+ netif_stop_queue(ndev); -+ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_TPE_BIT); -+ } -+ -+ priv->frame_handle++; -+ -+ return 0; -+} -+ -+static netdev_tx_t aspeed_can_start_xmit(struct sk_buff *skb, -+ struct net_device *ndev) -+{ -+ int ret; -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ unsigned long flags; -+ -+ if (can_dev_dropped_skb(ndev, skb)) -+ return NET_XMIT_DROP; -+ -+ spin_lock_irqsave(&priv->tx_lock, flags); -+ -+ ret = aspeed_can_start_frame_xmit(skb, ndev); -+ -+ spin_unlock_irqrestore(&priv->tx_lock, flags); -+ -+ if (ret) { -+ netdev_err(ndev, "Fail to transmit data!\n"); -+ netif_stop_queue(ndev); -+ return NET_XMIT_DROP; -+ } -+ -+ return NETDEV_TX_OK; -+} -+ -+static int aspeed_can_rx(struct net_device *ndev) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ struct net_device_stats *stats = &ndev->stats; -+ struct canfd_frame *cf; -+ struct sk_buff *skb; -+ u32 data; -+ u32 rx_stat; -+ u32 buf_ctrl_reg; -+ u32 reg_val; -+ u32 i; -+ -+ rx_stat = readl(priv->reg_base + CAN_CTRL); -+ if (!(rx_stat & CAN_CTRL_RSTAT_NOT_EMPTY_MASKT)) -+ return 0; -+ -+ buf_ctrl_reg = readl(priv->reg_base + CAN_RBUF_CTL); -+ if (buf_ctrl_reg & CAN_BUF_FDF_BIT) -+ skb = alloc_canfd_skb(ndev, &cf); -+ else -+ skb = alloc_can_skb(ndev, (struct can_frame **)&cf); -+ -+ if (!skb) { -+ stats->rx_dropped++; -+ return 0; -+ } -+ -+ reg_val = readl(priv->reg_base + CAN_RBUF_ID); -+ if (buf_ctrl_reg & CAN_BUF_IDE_BIT) { -+ cf->can_id = reg_val & CAN_BUF_ID_EFF_MASK; -+ cf->can_id |= CAN_EFF_FLAG; -+ } else { -+ cf->can_id = (reg_val & CAN_BUF_ID_BFF_MASK) >> -+ CAN_BUF_ID_BFF_BITOFF; -+ } -+ -+ if (buf_ctrl_reg & CAN_BUF_RMF_BIT) -+ cf->can_id |= CAN_RTR_FLAG; -+ -+ if (buf_ctrl_reg & CAN_BUF_FDF_BIT) -+ cf->len = can_fd_dlc2len(buf_ctrl_reg & CAN_BUF_DLC_MASK); -+ else -+ cf->len = can_cc_dlc2len(buf_ctrl_reg & CAN_BUF_DLC_MASK); -+ -+ /* Check the frame received is FD or not*/ -+ for (i = 0; i < cf->len; i += 4) { -+ data = readl(priv->reg_base + CAN_RBUF_DATA + i); -+ *(u32 *)(cf->data + i) = data; -+ } -+ -+ if (!(cf->can_id & CAN_RTR_FLAG)) -+ stats->rx_bytes += cf->len; -+ -+ stats->rx_packets++; -+ -+ /* release frame */ -+ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_RREL_BIT); -+ -+ netif_receive_skb(skb); -+ -+ return 1; -+} -+ -+static enum can_state aspeed_can_current_error_state(struct net_device *ndev) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ u32 status; -+ u32 rx_cnt; -+ u32 tx_cnt; -+ u32 ctrl; -+ -+ ctrl = readl(priv->reg_base + CAN_CTRL); -+ status = readl(priv->reg_base + CAN_INTF); -+ rx_cnt = (readl(priv->reg_base + CAN_ERR_STAT) & CAN_ERR_RECNT_MASK) >> -+ CAN_ERR_RECNT_BITOFF; -+ tx_cnt = (readl(priv->reg_base + CAN_ERR_STAT) & CAN_ERR_TECNT_MASK) >> -+ CAN_ERR_TECNT_BITOFF; -+ -+ if (ctrl & CAN_CTRL_BUSOFF_BIT) -+ return CAN_STATE_BUS_OFF; -+ else if ((status & CAN_EPASS_BIT) == CAN_EPASS_BIT) -+ return CAN_STATE_ERROR_PASSIVE; -+ else if (rx_cnt > 96 || tx_cnt > 96) -+ return CAN_STATE_ERROR_WARNING; -+ else -+ return CAN_STATE_ERROR_ACTIVE; -+} -+ -+static void aspeed_can_set_error_state(struct net_device *ndev, -+ enum can_state new_state, -+ struct can_frame *cf) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ u32 ecr = readl(priv->reg_base + CAN_ERR_STAT); -+ u32 txerr = (ecr & CAN_ERR_RECNT_MASK) >> CAN_ERR_RECNT_BITOFF; -+ u32 rxerr = (ecr & CAN_ERR_TECNT_MASK) >> CAN_ERR_TECNT_BITOFF; -+ enum can_state tx_state = txerr >= rxerr ? new_state : 0; -+ enum can_state rx_state = txerr <= rxerr ? new_state : 0; -+ -+ /* non-ERROR states are handled elsewhere */ -+ if (WARN_ON(new_state > CAN_STATE_ERROR_PASSIVE)) -+ return; -+ -+ can_change_state(ndev, cf, tx_state, rx_state); -+ -+ if (cf) { -+ cf->can_id |= CAN_ERR_CNT; -+ cf->data[6] = txerr; -+ cf->data[7] = rxerr; -+ } -+} -+ -+static void aspeed_can_update_error_state_after_rxtx(struct net_device *ndev) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ enum can_state old_state = priv->can.state; -+ enum can_state new_state; -+ -+ /* changing error state due to successful frame RX/TX can only -+ * occur from these states -+ */ -+ if (old_state != CAN_STATE_ERROR_WARNING && -+ old_state != CAN_STATE_ERROR_PASSIVE) -+ return; -+ -+ new_state = aspeed_can_current_error_state(ndev); -+ -+ if (new_state != old_state) { -+ struct sk_buff *skb; -+ struct can_frame *cf; -+ -+ skb = alloc_can_err_skb(ndev, &cf); -+ -+ aspeed_can_set_error_state(ndev, new_state, skb ? cf : NULL); -+ -+ if (skb) -+ netif_rx(skb); -+ } -+} -+ -+static void aspeed_can_err_interrupt(struct net_device *ndev, u32 isr) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ struct net_device_stats *stats = &ndev->stats; -+ struct can_frame cf = { }; -+ u32 err; -+ u32 ctrl; -+ u32 koer; -+ u32 recnt; -+ u32 tecnt; -+ -+ netdev_err(ndev, "in error interrupt.\n"); -+ -+ aspeed_can_reg_dump(ndev); -+ -+ err = readl(priv->reg_base + CAN_ERR_STAT); -+ ctrl = readl(priv->reg_base + CAN_CTRL); -+ -+ koer = (err & CAN_ERR_KOER_MASK) >> CAN_ERR_KOER_BITOFF; -+ recnt = (err & CAN_ERR_RECNT_MASK) >> CAN_ERR_RECNT_BITOFF; -+ tecnt = (err & CAN_ERR_TECNT_MASK) >> CAN_ERR_TECNT_BITOFF; -+ -+ if (ctrl & CAN_CTRL_BUSOFF_BIT) { -+ priv->can.state = CAN_STATE_BUS_OFF; -+ priv->can.can_stats.bus_off++; -+ /* Leave device in Config Mode in bus-off state */ -+ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_RST_BIT); -+ can_bus_off(ndev); -+ cf.can_id |= CAN_ERR_BUSOFF; -+ } else { -+ enum can_state new_state = aspeed_can_current_error_state(ndev); -+ -+ if (new_state != priv->can.state) -+ aspeed_can_set_error_state(ndev, new_state, &cf); -+ } -+ -+ if (isr & CAN_INT_ALIF_BIT) { -+ priv->can.can_stats.arbitration_lost++; -+ cf.can_id |= CAN_ERR_LOSTARB; -+ cf.data[0] = CAN_ERR_LOSTARB_UNSPEC; -+ } -+ -+ if (isr & CAN_INT_ROIF_BIT) { -+ stats->rx_over_errors++; -+ stats->rx_errors++; -+ cf.can_id |= CAN_ERR_CRTL; -+ cf.data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; -+ } -+ -+ /* Check for error interrupt */ -+ if (isr & CAN_INT_BEIF_BIT) { -+ bool berr_reporting = false; -+ -+ if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) { -+ berr_reporting = true; -+ cf.can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; -+ } -+ -+ if (koer == KOER_ACK_ERROR_MASK) { -+ netdev_err(ndev, "ACK error exists\n"); -+ stats->tx_errors++; -+ if (berr_reporting) { -+ cf.can_id |= CAN_ERR_ACK; -+ cf.data[3] = CAN_ERR_PROT_LOC_ACK; -+ } -+ } -+ -+ if (koer == KOER_BIT_ERROR_MASK) { -+ netdev_err(ndev, "BIT error exists\n"); -+ stats->tx_errors++; -+ if (berr_reporting) { -+ cf.can_id |= CAN_ERR_PROT; -+ cf.data[2] = CAN_ERR_PROT_BIT; -+ } -+ } -+ -+ if (koer == KOER_STUFF_ERROR_MASK) { -+ netdev_err(ndev, "STUFF error exists\n"); -+ stats->rx_errors++; -+ if (berr_reporting) { -+ cf.can_id |= CAN_ERR_PROT; -+ cf.data[2] = CAN_ERR_PROT_STUFF; -+ } -+ } -+ -+ if (koer == KOER_FORM_ERROR_MASK) { -+ netdev_err(ndev, "FORM error exists\n"); -+ stats->rx_errors++; -+ if (berr_reporting) { -+ cf.can_id |= CAN_ERR_PROT; -+ cf.data[2] = CAN_ERR_PROT_FORM; -+ } -+ } -+ -+ if (koer == KOER_CRC_ERROR_MASK) { -+ netdev_err(ndev, "CRC error exists\n"); -+ stats->rx_errors++; -+ if (berr_reporting) { -+ cf.can_id |= CAN_ERR_PROT; -+ cf.data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; -+ } -+ } -+ -+ priv->can.can_stats.bus_error++; -+ } -+ -+ if (cf.can_id) { -+ struct can_frame *skb_cf; -+ struct sk_buff *skb = alloc_can_err_skb(ndev, &skb_cf); -+ -+ if (skb) { -+ skb_cf->can_id |= cf.can_id; -+ memcpy(skb_cf->data, cf.data, CAN_ERR_DLC); -+ netif_rx(skb); -+ } -+ } -+} -+ -+static int aspeed_can_rx_poll(struct napi_struct *napi, int quota) -+{ -+ struct net_device *ndev = napi->dev; -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ int work_done = 0; -+ u32 rx_stat; -+ u32 ier; -+ -+ rx_stat = readl(priv->reg_base + CAN_CTRL); -+ -+ while ((rx_stat & CAN_CTRL_RSTAT_NOT_EMPTY_MASKT) != 0 && -+ (work_done < quota)) { -+ work_done += aspeed_can_rx(ndev); -+ rx_stat = readl(priv->reg_base + CAN_CTRL); -+ } -+ -+ if (work_done) -+ aspeed_can_update_error_state_after_rxtx(ndev); -+ -+ if (work_done < quota) { -+ if (napi_complete_done(napi, work_done)) { -+ ier = readl(priv->reg_base + CAN_INTE); -+ ier |= CAN_INT_RIE_BIT; -+ writel(ier, priv->reg_base + CAN_INTE); -+ } -+ } -+ -+ return work_done; -+} -+ -+static void aspeed_can_tx_interrupt(struct net_device *ndev, u32 intr_flag) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ struct net_device_stats *stats = &ndev->stats; -+ u32 frames_in_fifo; -+ unsigned long flags; -+ u32 can_ctrl; -+ u32 stauts_2; -+ u32 handle; -+ u32 skb_idx; -+ int ret; -+ -+ spin_lock_irqsave(&priv->tx_lock, flags); -+ -+ /* PTB */ -+ if (intr_flag & CAN_INT_TPIF_BIT) { -+ aspeed_can_clr_irq_bits(priv, CAN_INTF, CAN_INT_TPIF_BIT); -+ stats->tx_bytes += can_get_echo_skb(ndev, 0, NULL); -+ goto exit; -+ } -+ -+ /* STB */ -+ can_ctrl = readl(priv->reg_base + CAN_CTRL); -+ stauts_2 = readl(priv->reg_base + CAN_TSTAT); -+ -+ switch (priv->stb_mode_policy) { -+ case (STB_TX_MODE_ONE | STB_POLICY_PRIO): -+ aspeed_can_clr_irq_bits(priv, CAN_INTF, CAN_INT_TSIF_BIT); -+ -+ handle = (stauts_2 & CAN_TSTAT2_HANDLE_MASK) >> -+ CAN_TSTAT2_HANDLE_BITOFF; -+ skb_idx = aspeed_can_get_skb_idx(ndev, handle); -+ if (skb_idx == STB_INVALID_SKB_IDX) { -+ netdev_err(ndev, "fail to get skb idx (%x)\n", -+ STB_TX_MODE_ONE | STB_POLICY_PRIO); -+ } else { -+ stats->tx_bytes += can_get_echo_skb(ndev, skb_idx, NULL); -+ stats->tx_packets++; -+ ret = aspeed_can_drop_ring_obj(ndev, handle); -+ /* priv->tail_ptr = priv->tail_ptr.next; */ -+ if (ret < 0) { -+ netdev_err(ndev, "fail to drop a ring obj (%x)\n", -+ STB_TX_MODE_ONE | STB_POLICY_PRIO); -+ } -+ } -+ -+ /* something still in STB */ -+ if ((can_ctrl & CAN_CTRL_TSSTAT_MASK) != 0x0) -+ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_TSONE_BIT); -+ break; -+ -+ case (STB_TX_MODE_ALL | STB_POLICY_FIFO): -+ case (STB_TX_MODE_ALL | STB_POLICY_PRIO): -+ -+ aspeed_can_clr_irq_bits(priv, CAN_INTF, CAN_INT_TSIF_BIT); -+ -+ frames_in_fifo = aspeed_can_get_frame_num(ndev); -+ -+ /* Potential situation: A frame is submitted before this ISR. -+ * That new frame waits for transmission. -+ * This frame should be handled in the next ISR. -+ */ -+ if (can_ctrl & CAN_CTRL_TSSTAT_MASK) -+ frames_in_fifo--; -+ -+ while (frames_in_fifo != 0) { -+ stats->tx_bytes += can_get_echo_skb(ndev, -+ priv->tail_ptr->skb_idx, -+ NULL); -+ priv->tail_ptr->handle = STB_INVALID_HANDLE_VAL; -+ priv->tail_ptr = priv->tail_ptr->next; -+ stats->tx_packets++; -+ frames_in_fifo--; -+ } -+ -+ /* something still in STB */ -+ if (can_ctrl & CAN_CTRL_TSSTAT_MASK) -+ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_TSALL_BIT); -+ -+ break; -+ default: -+ /* including STB_TX_MODE_ONE and STB_POLICY_FIFO mode */ -+ aspeed_can_clr_irq_bits(priv, CAN_INTF, CAN_INT_TSIF_BIT); -+ -+ stats->tx_bytes += can_get_echo_skb(ndev, -+ priv->tail_ptr->skb_idx, -+ NULL); -+ priv->tail_ptr = priv->tail_ptr->next; -+ stats->tx_packets++; -+ -+ /* something in STB */ -+ if ((can_ctrl & CAN_CTRL_TSSTAT_MASK) != 0x0) -+ aspeed_can_set_bit(priv, CAN_CTRL, CAN_CTRL_TSONE_BIT); -+ } -+ -+exit: -+ netif_wake_queue(ndev); -+ -+ spin_unlock_irqrestore(&priv->tx_lock, flags); -+ -+ aspeed_can_update_error_state_after_rxtx(ndev); -+} -+ -+static irqreturn_t aspeed_can_interrupt(int irq, void *dev_id) -+{ -+ struct net_device *ndev = (struct net_device *)dev_id; -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ u32 isr; -+ u32 ier; -+ u32 isr_errors; -+ u32 rx_int_mask = CAN_INT_RIF_BIT; -+ -+ isr = readl(priv->reg_base + CAN_INTF); -+ if (!isr) -+ return IRQ_NONE; -+ -+ /* Check for Tx interrupt and Processing it */ -+ if (isr & (CAN_INT_TPIF_BIT | CAN_INT_TSIF_BIT)) -+ aspeed_can_tx_interrupt(ndev, isr); -+ -+ if (isr & CAN_INT_RAFIF_BIT) { -+ netdev_warn(ndev, "Receive buffer is almost full\n"); -+ aspeed_can_clr_irq_bits(priv, CAN_INTF, CAN_INT_RAFIF_BIT); -+ } -+ -+ if (isr & CAN_INT_RFIF_BIT) { -+ netdev_warn(ndev, "Receive buffer is full\n"); -+ aspeed_can_clr_irq_bits(priv, CAN_INTF, CAN_INT_RFIF_BIT); -+ } -+ -+ /* Check for the type of error interrupt and Processing it */ -+ isr_errors = isr & (CAN_INT_EIF_BIT | CAN_INT_ROIF_BIT | -+ CAN_INT_BEIF_BIT | CAN_INT_ALIF_BIT | -+ CAN_INT_EPIF_BIT | CAN_INT_EWARN_BIT); -+ if (isr_errors) { -+ aspeed_can_clr_irq_bits(priv, CAN_INTF, isr_errors); -+ aspeed_can_err_interrupt(ndev, isr); -+ } -+ -+ /* Check for the type of receive interrupt and Processing it */ -+ if (isr & rx_int_mask) { -+ aspeed_can_clr_irq_bits(priv, CAN_INTF, rx_int_mask); -+ ier = readl(priv->reg_base + CAN_INTE); -+ ier &= ~rx_int_mask; /* CAN_INT_RIE_BIT */ -+ writel(ier, priv->reg_base + CAN_INTE); -+ napi_schedule(&priv->napi); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static void aspeed_can_chip_stop(struct net_device *ndev) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ int ret; -+ -+ /* Disable interrupts and leave the can in configuration mode */ -+ ret = aspeed_can_set_reset_mode(ndev); -+ if (ret < 0) -+ netdev_dbg(ndev, "aspeed_can_set_reset_mode() Failed\n"); -+ -+ priv->can.state = CAN_STATE_STOPPED; -+} -+ -+static int aspeed_can_open(struct net_device *ndev) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ int ret; -+ -+ ret = pm_runtime_get_sync(priv->dev); -+ if (ret < 0) { -+ netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n", -+ __func__, ret); -+ goto err; -+ } -+ -+ ret = request_irq(ndev->irq, aspeed_can_interrupt, 0, -+ ndev->name, ndev); -+ if (ret < 0) { -+ netdev_err(ndev, "irq allocation for CAN failed\n"); -+ goto err; -+ } -+ -+ /* Set chip into reset mode */ -+ ret = aspeed_can_set_reset_mode(ndev); -+ if (ret < 0) { -+ netdev_err(ndev, "mode resetting failed!\n"); -+ goto err_irq; -+ } -+ -+ /* Common open */ -+ ret = open_candev(ndev); -+ if (ret) -+ goto err_irq; -+ -+ ret = aspeed_can_chip_start(ndev); -+ if (ret < 0) { -+ netdev_err(ndev, "aspeed_can_chip_start failed!\n"); -+ goto err_candev; -+ } -+ -+ napi_enable(&priv->napi); -+ netif_start_queue(ndev); -+ -+ return 0; -+ -+err_candev: -+ close_candev(ndev); -+err_irq: -+ free_irq(ndev->irq, ndev); -+err: -+ pm_runtime_put(priv->dev); -+ -+ return ret; -+} -+ -+static int aspeed_can_close(struct net_device *ndev) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ -+ netif_stop_queue(ndev); -+ napi_disable(&priv->napi); -+ aspeed_can_chip_stop(ndev); -+ free_irq(ndev->irq, ndev); -+ close_candev(ndev); -+ pm_runtime_put(priv->dev); -+ -+ return 0; -+} -+ -+static int aspeed_can_get_berr_counter(const struct net_device *ndev, -+ struct can_berr_counter *bec) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ int ret; -+ -+ ret = pm_runtime_get_sync(priv->dev); -+ if (ret < 0) { -+ netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n", -+ __func__, ret); -+ pm_runtime_put(priv->dev); -+ return ret; -+ } -+ -+ bec->rxerr = (readl(priv->reg_base + CAN_ERR_STAT) & -+ CAN_ERR_RECNT_MASK) >> CAN_ERR_RECNT_BITOFF; -+ bec->txerr = (readl(priv->reg_base + CAN_ERR_STAT) & -+ CAN_ERR_TECNT_MASK) >> CAN_ERR_TECNT_BITOFF; -+ -+ pm_runtime_put(priv->dev); -+ -+ return 0; -+} -+ -+static int aspeed_can_get_auto_tdcv(const struct net_device *ndev, u32 *tdcv) -+{ -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ u32 reg; -+ -+ reg = readl(priv->reg_base + CAN_BITITME); -+ *tdcv = (reg & CAN_TIMING_FD_SSPOFF_MASK) >> CAN_TIMING_FD_SSPOFF_BITOFF; -+ -+ return 0; -+} -+ -+static const struct net_device_ops aspeed_can_netdev_ops = { -+ .ndo_open = aspeed_can_open, -+ .ndo_stop = aspeed_can_close, -+ .ndo_start_xmit = aspeed_can_start_xmit, -+ .ndo_change_mtu = can_change_mtu, -+}; -+ -+static const struct ethtool_ops aspeed_can_ethtool_ops = { -+ .get_ts_info = ethtool_op_get_ts_info, -+}; -+ -+static int __maybe_unused aspeed_can_suspend(struct device *dev) -+{ -+ struct net_device *ndev = dev_get_drvdata(dev); -+ -+ if (netif_running(ndev)) { -+ netif_stop_queue(ndev); -+ netif_device_detach(ndev); -+ aspeed_can_chip_stop(ndev); -+ } -+ -+ return pm_runtime_force_suspend(dev); -+} -+ -+static int __maybe_unused aspeed_can_resume(struct device *dev) -+{ -+ struct net_device *ndev = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = pm_runtime_force_resume(dev); -+ if (ret) { -+ dev_err(dev, "pm_runtime_force_resume failed on resume\n"); -+ return ret; -+ } -+ -+ if (netif_running(ndev)) { -+ ret = aspeed_can_chip_start(ndev); -+ if (ret) { -+ dev_err(dev, "aspeed_can_chip_start failed on resume\n"); -+ return ret; -+ } -+ -+ netif_device_attach(ndev); -+ netif_start_queue(ndev); -+ } -+ -+ return 0; -+} -+ -+static int __maybe_unused aspeed_can_runtime_suspend(struct device *dev) -+{ -+ struct net_device *ndev = dev_get_drvdata(dev); -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ -+ clk_disable_unprepare(priv->clk); -+ -+ return 0; -+} -+ -+static int __maybe_unused aspeed_can_runtime_resume(struct device *dev) -+{ -+ struct net_device *ndev = dev_get_drvdata(dev); -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ int ret; -+ -+ ret = clk_prepare_enable(priv->clk); -+ if (ret) { -+ dev_err(dev, "Cannot enable clock.\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops aspeed_can_dev_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(aspeed_can_suspend, aspeed_can_resume) -+ SET_RUNTIME_PM_OPS(aspeed_can_runtime_suspend, aspeed_can_runtime_resume, NULL) -+}; -+ -+/* Match table for OF platform binding */ -+static const struct of_device_id aspeed_can_of_match[] = { -+ { .compatible = "aspeed,canfd", .data = NULL }, -+ { /* end of list */ }, -+}; -+MODULE_DEVICE_TABLE(of, aspeed_can_of_match); -+ -+static int aspeed_can_probe(struct platform_device *pdev) -+{ -+ struct net_device *ndev; -+ struct aspeed_can_priv *priv; -+ int ret; -+ /* Fixed to temporarily. */ -+ u32 rx_max = 3; -+ u32 can_clk; -+ -+ ndev = alloc_candev(sizeof(struct aspeed_can_priv), 4); -+ if (!ndev) -+ return -ENOMEM; -+ -+ priv = netdev_priv(ndev); -+ -+ priv->dev = &pdev->dev; -+ priv->reg_base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(priv->reg_base)) { -+ ret = PTR_ERR(priv->reg_base); -+ goto err; -+ }; -+ -+ priv->can.bittiming_const = &aspeed_can_bittiming_const; -+ priv->can.data_bittiming_const = &aspeed_canfd_bittiming_const; -+ priv->can.do_set_mode = aspeed_can_do_set_mode; -+ priv->can.do_get_berr_counter = aspeed_can_get_berr_counter; -+ priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | -+ CAN_CTRLMODE_BERR_REPORTING | -+ CAN_CTRLMODE_FD | -+ CAN_CTRLMODE_CC_LEN8_DLC | -+ CAN_CTRLMODE_TDC_AUTO; -+ priv->can.do_get_auto_tdcv = aspeed_can_get_auto_tdcv; -+ -+ priv->tx_max = 3; -+ spin_lock_init(&priv->tx_lock); -+ -+ /* Get IRQ for the device */ -+ ret = platform_get_irq(pdev, 0); -+ if (ret < 0) -+ goto err_free; -+ -+ ndev->irq = ret; -+ -+ /* We support local echo */ -+ ndev->flags |= IFF_ECHO; -+ -+ platform_set_drvdata(pdev, ndev); -+ SET_NETDEV_DEV(ndev, &pdev->dev); -+ ndev->netdev_ops = &aspeed_can_netdev_ops; -+ ndev->ethtool_ops = &aspeed_can_ethtool_ops; -+ -+ /* Getting the CAN can_clk info */ -+ priv->clk = devm_clk_get(&pdev->dev, NULL); -+ if (IS_ERR(priv->clk)) { -+ dev_err(&pdev->dev, "missing clock\n"); -+ return PTR_ERR(priv->clk); -+ } -+ -+ can_clk = clk_get_rate(priv->clk); -+ if (!can_clk) { -+ dev_err(&pdev->dev, "invalid clock\n"); -+ return -EINVAL; -+ } -+ -+ ret = clk_prepare_enable(priv->clk); -+ if (ret) { -+ dev_err(&pdev->dev, "can not enable the clock\n"); -+ return ret; -+ } -+ -+ priv->can.clock.freq = can_clk; -+ -+ priv->tb_mode = PTB_MODE; -+ if (of_property_read_bool(priv->dev->of_node, "can-stb-mode")) -+ priv->tb_mode = STB_MODE; -+ -+ priv->stb_mode_policy = STB_TX_MODE_ONE; -+ if (of_property_read_bool(priv->dev->of_node, "can-stb-tx-all")) -+ priv->stb_mode_policy = STB_TX_MODE_ALL; -+ -+ if (of_property_read_bool(priv->dev->of_node, "can-stb-priority")) -+ priv->stb_mode_policy |= STB_POLICY_PRIO; -+ else -+ priv->stb_mode_policy |= STB_POLICY_FIFO; -+ -+ priv->stb_ring = kzalloc(sizeof(*priv->stb_ring) * -+ STB_IDX_RING_SZ, GFP_KERNEL); -+ aspeed_can_stb_ring_obj_init(ndev); -+ -+ if (of_property_read_bool(priv->dev->of_node, "can-internal-loopback")) -+ priv->flag |= ASPEED_CAN_INTERNEL_LOOPBACK; -+ -+ priv->reset = devm_reset_control_get_exclusive(&pdev->dev, NULL); -+ if (IS_ERR(priv->reset)) -+ return PTR_ERR(priv->reset); -+ -+ reset_control_deassert(priv->reset); -+ -+ ret = aspeed_can_set_reset_mode(ndev); -+ if (ret < 0) -+ goto err; -+ -+ pm_runtime_enable(&pdev->dev); -+ ret = pm_runtime_get_sync(&pdev->dev); -+ if (ret < 0) { -+ netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n", -+ __func__, ret); -+ goto err_disableclks; -+ } -+ -+ netif_napi_add_weight(ndev, &priv->napi, aspeed_can_rx_poll, rx_max); -+ -+ ret = register_candev(ndev); -+ if (ret) { -+ dev_err(&pdev->dev, "fail to register failed (err=%d)\n", ret); -+ goto err_disableclks; -+ } -+ -+ pm_runtime_put(&pdev->dev); -+ -+ netdev_dbg(ndev, "reg_base = 0x%p, irq = %d, clock = %d\n", -+ priv->reg_base, ndev->irq, priv->can.clock.freq); -+ -+ return 0; -+ -+err_disableclks: -+ pm_runtime_put(priv->dev); -+ pm_runtime_disable(&pdev->dev); -+err_free: -+ free_candev(ndev); -+err: -+ kfree(priv->stb_ring); -+ -+ return ret; -+} -+ -+static void aspeed_can_remove(struct platform_device *pdev) -+{ -+ struct net_device *ndev = platform_get_drvdata(pdev); -+ struct aspeed_can_priv *priv = netdev_priv(ndev); -+ -+ reset_control_assert(priv->reset); -+ unregister_candev(ndev); -+ pm_runtime_disable(&pdev->dev); -+ kfree(priv->stb_ring); -+ -+ free_candev(ndev); -+} -+ -+static struct platform_driver aspeed_can_driver = { -+ .probe = aspeed_can_probe, -+ .remove = aspeed_can_remove, -+ .driver = { -+ .name = DRIVER_NAME, -+ .pm = &aspeed_can_dev_pm_ops, -+ .of_match_table = aspeed_can_of_match, -+ }, -+}; -+ -+module_platform_driver(aspeed_can_driver); -+ -+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 2026-04-08 18:03:48.332704918 +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 2026-04-08 18:03:48.332704918 +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,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 +291,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 +349,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 +378,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 +458,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 +586,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 +664,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 +823,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 +853,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 +930,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 +1032,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 +1778,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) -@@ -1812,12 +1865,377 @@ - 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; -@@ -1882,10 +2300,15 @@ - 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; -+ /* 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); -@@ -1913,47 +2336,37 @@ - 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; - } - -- 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; -@@ -1995,6 +2408,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 +2482,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 2026-04-08 18:03:48.332704918 +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,44 @@ - #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) -+ -+/* 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 ---- 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-04-08 18:03:49.259687981 +0000 -@@ -0,0 +1,361 @@ -+// 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, -+}; -+ -+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 & 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) -+{ -+ 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 2026-04-08 18:03:48.105709065 +0000 -@@ -62,6 +62,8 @@ - | FIELD_PREP(ASPEED_MDIO_DATA_MIIRDATA, data); - - iowrite32(ctrl, 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 2026-04-08 18:03:35.347942010 +0000 -@@ -47,6 +47,22 @@ - - If unsure, say Y if you have an Apple Silicon system. - -+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 2025-08-01 08:48:47.000000000 +0000 -+++ b/drivers/pci/controller/Makefile 2026-04-08 18:03:40.287851903 +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 2026-04-08 18:03:48.290705685 +0000 -@@ -0,0 +1,1182 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * PCIe host controller driver for ASPEED PCIe Bridge -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "../pci.h" -+ -+#define MAX_MSI_HOST_IRQS 64 -+ -+/* AST2600 AHBC Registers */ -+#define AHBC_KEY 0x00 -+#define AHBC_UNLOCK 0xAEED1A03 -+#define AHBC_ADDR_MAPPING 0x8C -+#define PCIE_RC_MEMORY_EN BIT(5) -+ -+/* AST2600 PCIe Host Controller Registers */ -+#define PEHR_MISC_10 0x10 -+#define DATALINK_REPORT_CAPABLE BIT(4) -+#define PEHR_MISC_14 0x14 -+#define HOTPLUG_CAPABLE_ENABLE BIT(6) -+#define HOTPLUG_SURPRISE_ENABLE BIT(5) -+#define ATTENTION_BUTTON_ENABLE BIT(0) -+#define PEHR_GLOBAL 0x30 -+#define RC_SYNC_RESET_DISABLE BIT(20) -+#define PCIE_RC_SLOT_ENABLE BIT(1) -+#define ROOT_COMPLEX_ID(x) ((x) << 4) -+#define PEHR_LOCK 0x7C -+#define PCIE_UNLOCK 0xa8 -+#define PEHR_LINK 0xC0 -+#define PCIE_LINK_STS BIT(5) -+ -+/* AST2600 H2X Controller Registers */ -+/* Common Registers*/ -+#define H2X_INT_STS 0x08 -+#define PCIE_TX_IDLE_CLEAR BIT(0) -+#define H2X_TX_DESC0 0x10 -+#define H2X_TX_DESC1 0x14 -+#define H2X_TX_DESC2 0x18 -+#define H2X_TX_DESC3 0x1C -+#define H2X_TX_DESC_DATA 0x20 -+#define H2X_STS 0x24 -+#define PCIE_TX_IDLE BIT(31) -+#define PCIE_STATUS_OF_TX GENMASK(25, 24) -+#define PCIE_RC_L_TX_COMPLETE BIT(24) -+#define PCIE_RC_H_TX_COMPLETE BIT(25) -+#define PCIE_TRIGGER_TX BIT(0) -+#define H2X_AHB_ADDR_CONFIG0 0x60 -+#define H2X_AHB_ADDR_CONFIG1 0x64 -+#define H2X_AHB_ADDR_CONFIG2 0x68 -+/* Device Registers */ -+#define H2X_DEV_CTRL 0x00 -+#define PCIE_RX_DMA_EN BIT(9) -+#define PCIE_RX_LINEAR BIT(8) -+#define PCIE_RX_MSI_SEL BIT(7) -+#define PCIE_RX_MSI_EN BIT(6) -+#define PCIE_UNLOCK_RX_BUFF BIT(4) -+#define PCIE_Wait_RX_TLP_CLR BIT(2) -+#define PCIE_RC_RX_ENABLE BIT(1) -+#define PCIE_RC_ENABLE BIT(0) -+#define H2X_DEV_STS 0x08 -+#define PCIE_RC_RX_DONE_ISR BIT(4) -+#define H2X_DEV_RX_DESC_DATA 0x0C -+#define H2X_DEV_RX_DESC1 0x14 -+#define H2X_DEV_TX_TAG 0x3C -+ -+/* AST2700 H2X */ -+#define H2X_CTRL 0x00 -+#define H2X_BRIDGE_EN BIT(0) -+#define H2X_BRIDGE_DIRECT_EN BIT(1) -+#define H2X_CFGE_INT_STS 0x08 -+#define CFGE_TX_IDLE BIT(0) -+#define CFGE_RX_BUSY BIT(1) -+#define H2X_CFGI_TLP 0x20 -+#define H2X_CFGI_WR_DATA 0x24 -+#define H2X_CFGI_CTRL 0x28 -+#define CFGI_TLP_FIRE BIT(0) -+#define H2X_CFGI_RET_DATA 0x2C -+#define H2X_CFGE_TLP_1ST 0x30 -+#define H2X_CFGE_TLP_NEXT 0x34 -+#define H2X_CFGE_CTRL 0x38 -+#define CFGE_TLP_FIRE BIT(0) -+#define H2X_CFGE_RET_DATA 0x3C -+#define H2X_REMAP_PREF_ADDR 0x70 -+#define H2X_REMAP_DIRECT_ADDR 0x78 -+ -+/* AST2700 PEHR */ -+#define PEHR_VID_DID 0x00 -+#define PEHR_MISC_44 0x44 -+#define ENABLE_SLOT_CAP BIT(12) -+#define PEHR_MISC_38 0x38 -+#define DATALINK_REPORT_CAP BIT(20) -+#define PEHR_MISC_3C 0x3C -+#define PEHR_MISC_58 0x58 -+#define LOCAL_SCALE_SUP BIT(0) -+#define PEHR_MISC_5C 0x5C -+#define PEHR_MISC_60 0x60 -+#define PORT_TPYE GENMASK(7, 4) -+#define PORT_TYPE_ROOT BIT(2) -+#define PEHR_MISC_70 0x70 -+#define PEHR_MISC_78 0x78 -+#define PEHR_MISC_1B8 0x1B8 -+#define SW_ATT_BTN BIT(0) -+#define PEHR_MISC_344 0x344 -+#define LINK_STATUS_GEN2 BIT(18) -+#define PEHR_MISC_358 0x358 -+#define LINK_STATUS_GEN4 BIT(8) -+ -+/* AST2700 SCU */ -+#define SCU_60 0x60 -+#define RC_E2M_PATH_EN BIT(0) -+#define RC_H2XS_PATH_EN BIT(16) -+#define RC_H2XD_PATH_EN BIT(17) -+#define RC_H2XX_PATH_EN BIT(18) -+#define RC_UPSTREAM_MEM_EN BIT(19) -+#define SCU_64 0x64 -+#define SCU_70 0x70 -+#define SCU_78 0x78 -+ -+/* TLP configuration type 0 and type 1 */ -+#define CRG_READ_FMTTYPE(type) (0x04000000 | (type << 24)) -+#define CRG_WRITE_FMTTYPE(type) (0x44000000 | (type << 24)) -+#define CRG_PAYLOAD_SIZE 0x01 /* 1 DWORD */ -+#define TLP_COMP_STATUS(s) (((s) >> 13) & 7) -+ -+struct aspeed_pcie_rc_platform { -+ int (*setup)(struct platform_device *pdev); -+ /* Interrupt Register Offset */ -+ int reg_intx_en; -+ int reg_intx_sts; -+ int reg_msi_en; -+ int reg_msi_sts; -+ int msi_support; -+ int msi_address; -+}; -+ -+struct aspeed_pcie { -+ struct pci_host_bridge *host; -+ struct device *dev; -+ void __iomem *reg; -+ struct regmap *ahbc; -+ struct regmap *cfg; -+ struct regmap *pciephy; -+ struct clk *clock; -+ const struct aspeed_pcie_rc_platform *platform; -+ -+ int domain; -+ u8 tx_tag; -+ int host_bus_num; -+ -+ struct reset_control *h2xrst; -+ struct reset_control *perst; -+ -+ struct irq_domain *irq_domain; -+ struct irq_domain *dev_domain; -+ struct irq_domain *msi_domain; -+ /* Protects MSI IRQ allocation and release */ -+ struct mutex lock; -+ -+ int hotplug_event; -+ struct gpio_desc *perst_ep_in; -+ struct gpio_desc *perst_rc_out; -+ struct gpio_desc *perst_owner; -+ struct delayed_work rst_dwork; -+ DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_HOST_IRQS); -+}; -+ -+static void aspeed_pcie_intx_mask_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_unmask_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 struct irq_chip aspeed_intx_irq_chip = { -+ .name = "ASPEED:IntX", -+ .irq_mask = aspeed_pcie_intx_mask_irq, -+ .irq_unmask = aspeed_pcie_intx_unmask_irq, -+}; -+ -+static int aspeed_pcie_intx_map(struct irq_domain *domain, unsigned int irq, -+ irq_hw_number_t hwirq) -+{ -+ irq_set_chip_and_handler(irq, &aspeed_intx_irq_chip, handle_level_irq); -+ irq_set_chip_data(irq, domain->host_data); -+ irq_set_status_flags(irq, IRQ_LEVEL); -+ -+ return 0; -+} -+ -+static const struct irq_domain_ops aspeed_intx_domain_ops = { -+ .map = aspeed_pcie_intx_map, -+}; -+ -+static irqreturn_t aspeed_pcie_intr_handler(int irq, void *dev_id) -+{ -+ struct aspeed_pcie *pcie = dev_id; -+ const struct aspeed_pcie_rc_platform *platform = pcie->platform; -+ unsigned long status; -+ unsigned long intx; -+ u32 bit; -+ int i; -+ -+ intx = readl(pcie->reg + platform->reg_intx_sts) & 0xf; -+ if (intx) { -+ for_each_set_bit(bit, &intx, PCI_NUM_INTX) -+ generic_handle_domain_irq(pcie->irq_domain, bit); -+ } -+ -+ if (IS_ENABLED(CONFIG_PCI_MSI)) { -+ for (i = 0; i < 2; i++) { -+ status = readl(pcie->reg + platform->reg_msi_sts + (i * 4)); -+ writel(status, pcie->reg + platform->reg_msi_sts + (i * 4)); -+ /* Workaround: AST2700 MSI needs to cleat status twice */ -+ if (of_device_is_compatible(pcie->dev->of_node, "aspeed,ast2700-pcie")) -+ writel(status, pcie->reg + platform->reg_msi_sts + (i * 4)); -+ if (!status) -+ continue; -+ -+ for_each_set_bit(bit, &status, 32) { -+ if (i) -+ bit += 32; -+ generic_handle_domain_irq(pcie->dev_domain, bit); -+ } -+ } -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static int aspeed_ast2600_rd_conf(struct pci_bus *bus, unsigned int devfn, -+ int where, int size, u32 *val) -+{ -+ struct aspeed_pcie *pcie = bus->sysdata; -+ u32 bdf_offset; -+ int rx_done_fail = 0, slot = PCI_SLOT(devfn); -+ u32 cfg_val, isr, type = 0; -+ u32 link_sts = 0; -+ int ret; -+ -+ /* Driver may set unlock RX buffere before triggering next TX config */ -+ writel(PCIE_UNLOCK_RX_BUFF | readl(pcie->reg + H2X_DEV_CTRL), -+ pcie->reg + H2X_DEV_CTRL); -+ -+ if (bus->number == pcie->host_bus_num && slot != 0 && slot != 8) -+ return PCIBIOS_DEVICE_NOT_FOUND; -+ type = (bus->number > pcie->host_bus_num); -+ -+ if (type) { -+ regmap_read(pcie->pciephy, PEHR_LINK, &link_sts); -+ if (!(link_sts & PCIE_LINK_STS)) -+ return PCIBIOS_DEVICE_NOT_FOUND; -+ } -+ -+ bdf_offset = ((bus->number) << 24) | (PCI_SLOT(devfn) << 19) | -+ (PCI_FUNC(devfn) << 16) | (where & ~3); -+ -+ pcie->tx_tag %= 0x7; -+ -+ regmap_write(pcie->cfg, H2X_TX_DESC0, 0x04000001 | (type << 24)); -+ regmap_write(pcie->cfg, H2X_TX_DESC1, 0x0000200f | (pcie->tx_tag << 8)); -+ regmap_write(pcie->cfg, H2X_TX_DESC2, bdf_offset); -+ regmap_write(pcie->cfg, H2X_TX_DESC3, 0x00000000); -+ -+ regmap_write_bits(pcie->cfg, H2X_STS, PCIE_TRIGGER_TX, PCIE_TRIGGER_TX); -+ -+ ret = regmap_read_poll_timeout(pcie->cfg, H2X_STS, cfg_val, -+ (cfg_val & PCIE_TX_IDLE), 0, 50); -+ if (ret) { -+ dev_err(pcie->dev, -+ "[%X:%02X:%02X.%02X]CR tx timeout sts: 0x%08x\n", -+ pcie->domain, bus->number, PCI_SLOT(devfn), -+ PCI_FUNC(devfn), cfg_val); -+ goto out; -+ } -+ -+ regmap_write_bits(pcie->cfg, H2X_INT_STS, PCIE_TX_IDLE_CLEAR, -+ PCIE_TX_IDLE_CLEAR); -+ -+ regmap_read(pcie->cfg, H2X_STS, &cfg_val); -+ switch (cfg_val & PCIE_STATUS_OF_TX) { -+ case PCIE_RC_L_TX_COMPLETE: -+ case PCIE_RC_H_TX_COMPLETE: -+ ret = readl_poll_timeout(pcie->reg + H2X_DEV_STS, isr, -+ (isr & PCIE_RC_RX_DONE_ISR), 0, 50); -+ if (ret) { -+ dev_err(pcie->dev, -+ "[%X:%02X:%02X.%02X]CR rx timeoutsts: 0x%08x\n", -+ pcie->domain, bus->number, PCI_SLOT(devfn), -+ PCI_FUNC(devfn), isr); -+ rx_done_fail = 1; -+ *val = ~0; -+ } -+ if (!rx_done_fail) { -+ if (readl(pcie->reg + H2X_DEV_RX_DESC1) & BIT(13)) -+ *val = ~0; -+ else -+ *val = readl(pcie->reg + H2X_DEV_RX_DESC_DATA); -+ } -+ -+ writel(PCIE_UNLOCK_RX_BUFF | readl(pcie->reg + H2X_DEV_CTRL), -+ pcie->reg + H2X_DEV_CTRL); -+ break; -+ case PCIE_STATUS_OF_TX: -+ *val = ~0; -+ break; -+ default: -+ regmap_read(pcie->cfg, H2X_DEV_RX_DESC_DATA, &cfg_val); -+ *val = cfg_val; -+ break; -+ } -+ -+ switch (size) { -+ case 1: -+ *val = (*val >> ((where & 3) * 8)) & 0xff; -+ break; -+ case 2: -+ *val = (*val >> ((where & 2) * 8)) & 0xffff; -+ break; -+ } -+ -+ if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) { -+ if (where == (0x80 + PCI_EXP_SLTSTA) && -+ bus->number == pcie->host_bus_num && -+ PCI_SLOT(devfn) == 0x8 && -+ PCI_FUNC(devfn) == 0x0 && -+ pcie->hotplug_event) -+ *val |= PCI_EXP_SLTSTA_ABP; -+ } -+ -+ ret = PCIBIOS_SUCCESSFUL; -+out: -+ writel(readl(pcie->reg + H2X_DEV_STS), pcie->reg + H2X_DEV_STS); -+ pcie->tx_tag++; -+ return ret; -+} -+ -+static int aspeed_ast2600_wr_conf(struct pci_bus *bus, unsigned int devfn, -+ int where, int size, u32 val) -+{ -+ u32 type = 0; -+ u32 shift = 8 * (where & 3); -+ u32 bdf_offset; -+ u8 byte_en = 0; -+ struct aspeed_pcie *pcie = bus->sysdata; -+ u32 isr, cfg_val; -+ int ret; -+ -+ if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) { -+ if (where == (0x80 + PCI_EXP_SLTSTA) && -+ bus->number == pcie->host_bus_num && -+ PCI_SLOT(devfn) == 0x8 && -+ PCI_FUNC(devfn) == 0x0 && -+ pcie->hotplug_event && -+ (val & PCI_EXP_SLTSTA_ABP)) { -+ pcie->hotplug_event = 0; -+ return PCIBIOS_SUCCESSFUL; -+ } -+ } -+ -+ /* Driver may set unlock RX buffere before triggering next TX config */ -+ writel(PCIE_UNLOCK_RX_BUFF | readl(pcie->reg + H2X_DEV_CTRL), -+ pcie->reg + H2X_DEV_CTRL); -+ -+ switch (size) { -+ case 1: -+ byte_en = 1 << (where % 4); -+ val = (val & 0xff) << shift; -+ break; -+ case 2: -+ byte_en = 0x3 << (2 * ((where >> 1) % 2)); -+ val = (val & 0xffff) << shift; -+ break; -+ default: -+ byte_en = 0xf; -+ break; -+ } -+ -+ type = (bus->number > pcie->host_bus_num); -+ -+ bdf_offset = (bus->number << 24) | (PCI_SLOT(devfn) << 19) | -+ (PCI_FUNC(devfn) << 16) | (where & ~3); -+ pcie->tx_tag %= 0x7; -+ -+ regmap_write(pcie->cfg, H2X_TX_DESC0, 0x44000001 | (type << 24)); -+ regmap_write(pcie->cfg, H2X_TX_DESC1, -+ 0x00002000 | (pcie->tx_tag << 8) | byte_en); -+ regmap_write(pcie->cfg, H2X_TX_DESC2, bdf_offset); -+ regmap_write(pcie->cfg, H2X_TX_DESC3, 0x00000000); -+ regmap_write(pcie->cfg, H2X_TX_DESC_DATA, val); -+ -+ regmap_write_bits(pcie->cfg, H2X_STS, PCIE_TRIGGER_TX, PCIE_TRIGGER_TX); -+ -+ ret = regmap_read_poll_timeout(pcie->cfg, H2X_STS, cfg_val, -+ (cfg_val & PCIE_TX_IDLE), 0, 50); -+ if (ret) { -+ dev_err(pcie->dev, -+ "[%X:%02X:%02X.%02X]CT tx timeout sts: 0x%08x\n", -+ pcie->domain, bus->number, PCI_SLOT(devfn), -+ PCI_FUNC(devfn), cfg_val); -+ ret = PCIBIOS_SET_FAILED; -+ goto out; -+ } -+ -+ regmap_write_bits(pcie->cfg, H2X_INT_STS, PCIE_TX_IDLE_CLEAR, -+ PCIE_TX_IDLE_CLEAR); -+ -+ regmap_read(pcie->cfg, H2X_STS, &cfg_val); -+ switch (cfg_val & PCIE_STATUS_OF_TX) { -+ case PCIE_RC_L_TX_COMPLETE: -+ case PCIE_RC_H_TX_COMPLETE: -+ ret = readl_poll_timeout(pcie->reg + H2X_DEV_STS, isr, -+ (isr & PCIE_RC_RX_DONE_ISR), 0, 50); -+ if (ret) { -+ dev_err(pcie->dev, -+ "[%X:%02X:%02X.%02X]CT rx timeout sts: 0x%08x\n", -+ pcie->domain, bus->number, PCI_SLOT(devfn), -+ PCI_FUNC(devfn), isr); -+ ret = PCIBIOS_SET_FAILED; -+ goto out; -+ } -+ break; -+ } -+ ret = PCIBIOS_SUCCESSFUL; -+out: -+ writel(readl(pcie->reg + H2X_DEV_STS), pcie->reg + H2X_DEV_STS); -+ pcie->tx_tag++; -+ return ret; -+} -+ -+static bool aspeed_ast2700_get_link(struct aspeed_pcie *pcie) -+{ -+ u32 reg; -+ bool link; -+ -+ if (pcie->domain == 2) { -+ regmap_read(pcie->pciephy, PEHR_MISC_344, ®); -+ link = !!(reg & LINK_STATUS_GEN2); -+ } else { -+ regmap_read(pcie->pciephy, PEHR_MISC_358, ®); -+ link = !!(reg & LINK_STATUS_GEN4); -+ } -+ -+ return link; -+} -+ -+static int aspeed_ast2700_rd_conf(struct pci_bus *bus, unsigned int devfn, -+ int where, int size, u32 *val) -+{ -+ struct aspeed_pcie *pcie = bus->sysdata; -+ u32 bdf_offset, status; -+ u8 type; -+ int ret; -+ -+ if ((bus->number == pcie->host_bus_num && devfn != 0)) -+ return PCIBIOS_DEVICE_NOT_FOUND; -+ -+ if (bus->number == pcie->host_bus_num) { -+ /* Internal access to bridge */ -+ writel(0xF << 16 | (where & ~3), pcie->reg + H2X_CFGI_TLP); -+ writel(CFGI_TLP_FIRE, pcie->reg + H2X_CFGI_CTRL); -+ *val = readl(pcie->reg + H2X_CFGI_RET_DATA); -+ } else { -+ if (!aspeed_ast2700_get_link(pcie)) -+ return PCIBIOS_DEVICE_NOT_FOUND; -+ -+ bdf_offset = ((bus->number) << 24) | (PCI_SLOT(devfn) << 19) | -+ (PCI_FUNC(devfn) << 16) | (where & ~3); -+ -+ pcie->tx_tag %= 0xF; -+ -+ type = (bus->number == (pcie->host_bus_num + 1)) ? -+ PCI_HEADER_TYPE_NORMAL : -+ PCI_HEADER_TYPE_BRIDGE; -+ -+ writel(CRG_READ_FMTTYPE(type) | CRG_PAYLOAD_SIZE, pcie->reg + H2X_CFGE_TLP_1ST); -+ writel(0x40100F | (pcie->tx_tag << 8), pcie->reg + H2X_CFGE_TLP_NEXT); -+ writel(bdf_offset, pcie->reg + H2X_CFGE_TLP_NEXT); -+ writel(CFGE_TX_IDLE | CFGE_RX_BUSY, pcie->reg + H2X_CFGE_INT_STS); -+ writel(CFGE_TLP_FIRE, pcie->reg + H2X_CFGE_CTRL); -+ -+ ret = readl_poll_timeout(pcie->reg + H2X_CFGE_INT_STS, status, -+ (status & CFGE_TX_IDLE), 0, 50); -+ if (ret) { -+ dev_err(pcie->dev, -+ "[%X:%02X:%02X.%02X]CR tx timeout sts: 0x%08x\n", -+ pcie->domain, bus->number, PCI_SLOT(devfn), -+ PCI_FUNC(devfn), status); -+ goto out; -+ } -+ -+ ret = readl_poll_timeout(pcie->reg + H2X_CFGE_INT_STS, status, -+ (status & CFGE_RX_BUSY), 0, 50000); -+ if (ret) { -+ dev_err(pcie->dev, -+ "[%X:%02X:%02X.%02X]CR rx timeoutsts: 0x%08x\n", -+ pcie->domain, bus->number, PCI_SLOT(devfn), -+ PCI_FUNC(devfn), status); -+ goto out; -+ } -+ *val = readl(pcie->reg + H2X_CFGE_RET_DATA); -+ } -+ -+ switch (size) { -+ case 1: -+ *val = (*val >> ((where & 3) * 8)) & 0xff; -+ break; -+ case 2: -+ *val = (*val >> ((where & 2) * 8)) & 0xffff; -+ break; -+ } -+ -+ writel(status, pcie->reg + H2X_CFGE_INT_STS); -+ pcie->tx_tag++; -+ return PCIBIOS_SUCCESSFUL; -+out: -+ *val = ~0; -+ writel(status, pcie->reg + H2X_CFGE_INT_STS); -+ pcie->tx_tag++; -+ return PCIBIOS_SET_FAILED; -+} -+ -+static int aspeed_ast2700_wr_conf(struct pci_bus *bus, unsigned int devfn, -+ int where, int size, u32 val) -+{ -+ struct aspeed_pcie *pcie = bus->sysdata; -+ u32 shift = 8 * (where & 3); -+ u8 byte_en; -+ u32 bdf_offset, status, type; -+ int ret; -+ -+ if ((bus->number == pcie->host_bus_num && devfn != 0)) -+ return PCIBIOS_DEVICE_NOT_FOUND; -+ -+ switch (size) { -+ case 1: -+ byte_en = 1 << (where % 4); -+ val = (val & 0xff) << shift; -+ break; -+ case 2: -+ byte_en = 0x3 << (2 * ((where >> 1) % 2)); -+ val = (val & 0xffff) << shift; -+ break; -+ default: -+ byte_en = 0xf; -+ break; -+ } -+ -+ if (bus->number == pcie->host_bus_num) { -+ /* Internal access to bridge */ -+ writel(0x100000 | byte_en << 16 | (where & ~3), pcie->reg + H2X_CFGI_TLP); -+ writel(val, pcie->reg + H2X_CFGI_WR_DATA); -+ writel(CFGI_TLP_FIRE, pcie->reg + H2X_CFGI_CTRL); -+ } else { -+ if (!aspeed_ast2700_get_link(pcie)) -+ return PCIBIOS_SET_FAILED; -+ -+ bdf_offset = (bus->number << 24) | (PCI_SLOT(devfn) << 19) | -+ (PCI_FUNC(devfn) << 16) | (where & ~3); -+ pcie->tx_tag %= 0xF; -+ -+ type = (bus->number == (pcie->host_bus_num + 1)) ? -+ PCI_HEADER_TYPE_NORMAL : -+ PCI_HEADER_TYPE_BRIDGE; -+ -+ writel(CRG_WRITE_FMTTYPE(type) | CRG_PAYLOAD_SIZE, pcie->reg + H2X_CFGE_TLP_1ST); -+ writel(0x401000 | (pcie->tx_tag << 8) | byte_en, pcie->reg + H2X_CFGE_TLP_NEXT); -+ writel(bdf_offset, pcie->reg + H2X_CFGE_TLP_NEXT); -+ writel(val, pcie->reg + H2X_CFGE_TLP_NEXT); -+ writel(CFGE_TX_IDLE | CFGE_RX_BUSY, pcie->reg + H2X_CFGE_INT_STS); -+ writel(CFGE_TLP_FIRE, pcie->reg + H2X_CFGE_CTRL); -+ -+ ret = readl_poll_timeout(pcie->reg + H2X_CFGE_INT_STS, status, -+ (status & CFGE_TX_IDLE), 0, 50); -+ if (ret) { -+ dev_err(pcie->dev, -+ "[%X:%02X:%02X.%02X]CT tx timeout sts: 0x%08x\n", -+ pcie->domain, bus->number, PCI_SLOT(devfn), -+ PCI_FUNC(devfn), status); -+ ret = PCIBIOS_SET_FAILED; -+ goto out; -+ } -+ -+ ret = readl_poll_timeout(pcie->reg + H2X_CFGE_INT_STS, status, -+ (status & CFGE_RX_BUSY), 0, 50000); -+ if (ret) { -+ dev_err(pcie->dev, -+ "[%X:%02X:%02X.%02X]CT rx timeout sts: 0x%08x\n", -+ pcie->domain, bus->number, PCI_SLOT(devfn), -+ PCI_FUNC(devfn), status); -+ ret = PCIBIOS_SET_FAILED; -+ goto out; -+ } -+ -+ (void)readl(pcie->reg + H2X_CFGE_RET_DATA); -+ } -+ ret = PCIBIOS_SUCCESSFUL; -+out: -+ writel(status, pcie->reg + H2X_CFGE_INT_STS); -+ pcie->tx_tag++; -+ return ret; -+} -+ -+static struct pci_ops aspeed_ast2600_pcie_ops = { -+ .read = aspeed_ast2600_rd_conf, -+ .write = aspeed_ast2600_wr_conf, -+}; -+ -+static struct pci_ops aspeed_ast2700_pcie_ops = { -+ .read = aspeed_ast2700_rd_conf, -+ .write = aspeed_ast2700_wr_conf, -+}; -+ -+#ifdef CONFIG_PCI_MSI -+static void aspeed_msi_compose_msi_msg(struct irq_data *data, -+ struct msi_msg *msg) -+{ -+ struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(data); -+ -+ msg->address_hi = 0; -+ msg->address_lo = pcie->platform->msi_address; -+ msg->data = data->hwirq; -+} -+ -+static int aspeed_msi_set_affinity(struct irq_data *irq_data, -+ const struct cpumask *mask, bool force) -+{ -+ return -EINVAL; -+} -+ -+static struct irq_chip aspeed_msi_bottom_irq_chip = { -+ .name = "ASPEED MSI", -+ .irq_compose_msi_msg = aspeed_msi_compose_msi_msg, -+ .irq_set_affinity = aspeed_msi_set_affinity, -+}; -+ -+static int aspeed_irq_msi_domain_alloc(struct irq_domain *domain, -+ unsigned int virq, unsigned int nr_irqs, -+ void *args) -+{ -+ struct aspeed_pcie *pcie = domain->host_data; -+ int bit; -+ int i; -+ -+ mutex_lock(&pcie->lock); -+ -+ bit = bitmap_find_free_region(pcie->msi_irq_in_use, MAX_MSI_HOST_IRQS, -+ get_count_order(nr_irqs)); -+ -+ mutex_unlock(&pcie->lock); -+ -+ if (bit < 0) -+ return -ENOSPC; -+ -+ for (i = 0; i < nr_irqs; i++) { -+ irq_domain_set_info(domain, virq + i, bit + i, -+ &aspeed_msi_bottom_irq_chip, -+ domain->host_data, handle_simple_irq, NULL, -+ NULL); -+ } -+ -+ return 0; -+} -+ -+static void aspeed_irq_msi_domain_free(struct irq_domain *domain, -+ unsigned int virq, unsigned int nr_irqs) -+{ -+ struct irq_data *data = irq_domain_get_irq_data(domain, virq); -+ struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(data); -+ -+ mutex_lock(&pcie->lock); -+ -+ bitmap_release_region(pcie->msi_irq_in_use, data->hwirq, -+ get_count_order(nr_irqs)); -+ -+ mutex_unlock(&pcie->lock); -+} -+ -+static const struct irq_domain_ops aspeed_msi_domain_ops = { -+ .alloc = aspeed_irq_msi_domain_alloc, -+ .free = aspeed_irq_msi_domain_free, -+}; -+ -+static struct irq_chip aspeed_msi_irq_chip = { -+ .name = "PCIe MSI", -+ .irq_enable = pci_msi_unmask_irq, -+ .irq_disable = pci_msi_mask_irq, -+ .irq_mask = pci_msi_mask_irq, -+ .irq_unmask = pci_msi_unmask_irq, -+}; -+ -+static struct msi_domain_info aspeed_msi_domain_info = { -+ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | -+ MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX), -+ .chip = &aspeed_msi_irq_chip, -+}; -+#endif -+ -+static void aspeed_pcie_irq_domain_free(struct aspeed_pcie *pcie) -+{ -+ if (pcie->irq_domain) { -+ irq_domain_remove(pcie->irq_domain); -+ pcie->irq_domain = NULL; -+ } -+#ifdef CONFIG_PCI_MSI -+ if (pcie->msi_domain) { -+ irq_domain_remove(pcie->msi_domain); -+ pcie->msi_domain = NULL; -+ } -+ -+ if (pcie->dev_domain) { -+ irq_domain_remove(pcie->dev_domain); -+ pcie->dev_domain = NULL; -+ } -+#endif -+} -+ -+static int aspeed_pcie_init_irq_domain(struct aspeed_pcie *pcie) -+{ -+ struct device *dev = pcie->dev; -+ struct device_node *node = dev->of_node; -+ struct device_node *pcie_intc_node; -+ int ret; -+ -+ pcie_intc_node = of_get_next_child(node, NULL); -+ if (!pcie_intc_node) -+ return dev_err_probe(dev, -ENODEV, "No PCIe Intc node found\n"); -+ -+ pcie->irq_domain = -+ irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, &aspeed_intx_domain_ops, pcie); -+ of_node_put(pcie_intc_node); -+ if (!pcie->irq_domain) { -+ ret = dev_err_probe(dev, -ENOMEM, "failed to get an INTx IRQ domain\n"); -+ goto err; -+ } -+ -+ 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); -+ if (!pcie->dev_domain) { -+ ret = dev_err_probe(pcie->dev, -ENOMEM, "failed to create IRQ domain\n"); -+ goto err; -+ } -+ -+ pcie->msi_domain = pci_msi_create_irq_domain(dev_fwnode(pcie->dev), &aspeed_msi_domain_info, -+ pcie->dev_domain); -+ if (!pcie->msi_domain) { -+ ret = dev_err_probe(pcie->dev, -ENOMEM, "failed to create MSI domain\n"); -+ goto err; -+ } -+ -+ writel(~0, pcie->reg + pcie->platform->reg_msi_en); -+ writel(~0, pcie->reg + pcie->platform->reg_msi_en + 0x04); -+ writel(~0, pcie->reg + pcie->platform->reg_msi_sts); -+ writel(~0, pcie->reg + pcie->platform->reg_msi_sts + 0x04); -+#endif -+ return 0; -+err: -+ aspeed_pcie_irq_domain_free(pcie); -+ return ret; -+} -+ -+static void aspeed_pcie_port_init(struct aspeed_pcie *pcie) -+{ -+ u32 link_sts = 0; -+ -+ regmap_write(pcie->pciephy, PEHR_LOCK, PCIE_UNLOCK); -+ -+ if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) { -+ regmap_write(pcie->pciephy, PEHR_GLOBAL, -+ RC_SYNC_RESET_DISABLE | ROOT_COMPLEX_ID(0x3) | PCIE_RC_SLOT_ENABLE); -+ regmap_write(pcie->pciephy, PEHR_MISC_10, 0xd7040022 | DATALINK_REPORT_CAPABLE); -+ regmap_write(pcie->pciephy, PEHR_MISC_14, -+ HOTPLUG_CAPABLE_ENABLE | HOTPLUG_SURPRISE_ENABLE | -+ ATTENTION_BUTTON_ENABLE); -+ } else { -+ regmap_write(pcie->pciephy, PEHR_GLOBAL, ROOT_COMPLEX_ID(0x3)); -+ } -+ -+ if (pcie->perst_rc_out) { -+ mdelay(100); -+ gpiod_set_value(pcie->perst_rc_out, 1); -+ } -+ -+ reset_control_deassert(pcie->perst); -+ mdelay(500); -+ -+ writel(PCIE_RX_DMA_EN | PCIE_RX_LINEAR | PCIE_RX_MSI_SEL | PCIE_RX_MSI_EN | -+ PCIE_Wait_RX_TLP_CLR | PCIE_RC_RX_ENABLE | PCIE_RC_ENABLE, -+ pcie->reg + H2X_DEV_CTRL); -+ -+ writel(0x28, pcie->reg + H2X_DEV_TX_TAG); -+ -+ regmap_read(pcie->pciephy, PEHR_LINK, &link_sts); -+ if (link_sts & PCIE_LINK_STS) -+ dev_info(pcie->dev, "PCIE- Link up\n"); -+ else -+ dev_info(pcie->dev, "PCIE- Link down\n"); -+} -+ -+static ssize_t hotplug_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ struct aspeed_pcie *pcie = dev_get_drvdata(dev); -+ -+ pcie->hotplug_event = 1; -+ -+ if (of_device_is_compatible(pcie->dev->of_node, "aspeed,ast2700-pcie")) { -+ regmap_write_bits(pcie->pciephy, PEHR_MISC_1B8, SW_ATT_BTN, SW_ATT_BTN); -+ regmap_clear_bits(pcie->pciephy, PEHR_MISC_1B8, SW_ATT_BTN); -+ } -+ -+ return len; -+} -+ -+static DEVICE_ATTR_WO(hotplug); -+ -+static void aspeed_pcie_reset_work(struct work_struct *work) -+{ -+ struct aspeed_pcie *pcie = -+ container_of(work, typeof(*pcie), rst_dwork.work); -+ struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); -+ struct pci_bus *parent = host->bus; -+ struct pci_dev *dev, *temp; -+ u32 link_sts = 0; -+ u16 command; -+ -+ pci_lock_rescan_remove(); -+ -+ list_for_each_entry_safe_reverse(dev, temp, &parent->devices, -+ bus_list) { -+ pci_dev_get(dev); -+ pci_stop_and_remove_bus_device(dev); -+ /* -+ * Ensure that no new Requests will be generated from -+ * the device. -+ */ -+ pci_read_config_word(dev, PCI_COMMAND, &command); -+ command &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_SERR); -+ command |= PCI_COMMAND_INTX_DISABLE; -+ pci_write_config_word(dev, PCI_COMMAND, command); -+ pci_dev_put(dev); -+ } -+ -+ /* -+ * With perst_rc_out GPIO, the perst will only affect our PCIe controller, so it only -+ * needs to stay low for 1ms. -+ * Without perst_rc_out GPIO, the perst will affect external devices, so it needs to -+ * follow the spec and stay low for at least 100ms. -+ */ -+ reset_control_assert(pcie->perst); -+ if (pcie->perst_rc_out) { -+ gpiod_set_value(pcie->perst_rc_out, 0); -+ mdelay(1); -+ } else { -+ mdelay(100); -+ } -+ reset_control_deassert(pcie->perst); -+ if (pcie->perst_rc_out) { -+ mdelay(100); -+ gpiod_set_value(pcie->perst_rc_out, 1); -+ } -+ mdelay(10); -+ -+ regmap_read(pcie->pciephy, PEHR_LINK, &link_sts); -+ if (link_sts & PCIE_LINK_STS) -+ dev_info(pcie->dev, "PCIE- Link up\n"); -+ else -+ dev_info(pcie->dev, "PCIE- Link down\n"); -+ -+ pci_rescan_bus(host->bus); -+ pci_unlock_rescan_remove(); -+} -+ -+static irqreturn_t pcie_rst_irq_handler(int irq, void *dev_id) -+{ -+ struct aspeed_pcie *pcie = dev_id; -+ -+ schedule_delayed_work(&pcie->rst_dwork, 0); -+ -+ return IRQ_HANDLED; -+} -+ -+static int aspeed_ast2600_setup(struct platform_device *pdev) -+{ -+ struct aspeed_pcie *pcie = platform_get_drvdata(pdev); -+ struct device *dev = pcie->dev; -+ int ret; -+ -+ if (pcie->host_bus_num != 0x80) { -+ dev_err(dev, "AST2600 only supports to start bus number 0x80\n"); -+ return -EINVAL; -+ } -+ -+ pcie->ahbc = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,ahbc"); -+ if (IS_ERR(pcie->ahbc)) -+ return dev_err_probe(dev, PTR_ERR(pcie->ahbc), "failed to map ahbc base\n"); -+ -+ reset_control_assert(pcie->h2xrst); -+ mdelay(5); -+ reset_control_deassert(pcie->h2xrst); -+ -+ regmap_write(pcie->ahbc, AHBC_KEY, AHBC_UNLOCK); -+ regmap_update_bits(pcie->ahbc, AHBC_ADDR_MAPPING, PCIE_RC_MEMORY_EN, PCIE_RC_MEMORY_EN); -+ regmap_write(pcie->ahbc, AHBC_KEY, 0x1); -+ -+ regmap_write(pcie->cfg, H2X_AHB_ADDR_CONFIG0, 0xe0006000); -+ regmap_write(pcie->cfg, H2X_AHB_ADDR_CONFIG1, 0); -+ regmap_write(pcie->cfg, H2X_AHB_ADDR_CONFIG2, ~0); -+ -+ regmap_write(pcie->cfg, H2X_CTRL, H2X_BRIDGE_EN); -+ -+ aspeed_pcie_port_init(pcie); -+ -+ pcie->host->ops = &aspeed_ast2600_pcie_ops; -+ -+ pcie->perst_ep_in = devm_gpiod_get_optional(pcie->dev, "perst-ep-in", GPIOD_IN); -+ if (pcie->perst_ep_in) { -+ gpiod_set_debounce(pcie->perst_ep_in, 100); -+ irq_set_irq_type(gpiod_to_irq(pcie->perst_ep_in), IRQ_TYPE_EDGE_BOTH); -+ ret = devm_request_irq(pcie->dev, gpiod_to_irq(pcie->perst_ep_in), -+ pcie_rst_irq_handler, IRQF_SHARED, "PERST monitor", pcie); -+ if (ret) -+ return dev_err_probe(pcie->dev, ret, "Failed to request gpio irq\n"); -+ INIT_DELAYED_WORK(&pcie->rst_dwork, aspeed_pcie_reset_work); -+ } -+ pcie->perst_owner = -+ devm_gpiod_get_optional(pcie->dev, "perst-owner", GPIOD_OUT_HIGH); -+ -+ return 0; -+} -+ -+static int aspeed_ast2700_setup(struct platform_device *pdev) -+{ -+ struct aspeed_pcie *pcie = platform_get_drvdata(pdev); -+ struct device *dev = pcie->dev; -+ u32 cfg_val; -+ -+ reset_control_assert(pcie->perst); -+ -+ regmap_write(pcie->pciephy, PEHR_MISC_70, 0xa00c0); -+ regmap_write(pcie->pciephy, PEHR_MISC_78, 0x80030); -+ regmap_write(pcie->pciephy, PEHR_MISC_58, LOCAL_SCALE_SUP); -+ -+ regmap_update_bits(pcie->cfg, SCU_60, -+ RC_E2M_PATH_EN | RC_H2XS_PATH_EN | RC_H2XD_PATH_EN | RC_H2XX_PATH_EN | -+ RC_UPSTREAM_MEM_EN, -+ RC_E2M_PATH_EN | RC_H2XS_PATH_EN | RC_H2XD_PATH_EN | RC_H2XX_PATH_EN | -+ RC_UPSTREAM_MEM_EN); -+ regmap_write(pcie->cfg, SCU_64, 0xff00ff00); -+ regmap_write(pcie->cfg, SCU_70, 0); -+ regmap_write(pcie->cfg, SCU_78, (pcie->domain == 1) ? BIT(31) : 0); -+ -+ reset_control_assert(pcie->h2xrst); -+ mdelay(10); -+ reset_control_deassert(pcie->h2xrst); -+ -+ regmap_write(pcie->pciephy, PEHR_MISC_5C, 0x40000000); -+ regmap_read(pcie->pciephy, PEHR_MISC_60, &cfg_val); -+ regmap_write(pcie->pciephy, PEHR_MISC_60, -+ (cfg_val & ~PORT_TPYE) | FIELD_PREP(PORT_TPYE, PORT_TYPE_ROOT)); -+ -+ writel(0, pcie->reg + H2X_CTRL); -+ writel(H2X_BRIDGE_EN | H2X_BRIDGE_DIRECT_EN, pcie->reg + H2X_CTRL); -+ -+ /* The BAR mapping: -+ * CPU Node0(domain 0): 0x60000000 -+ * CPU Node1(domain 1): 0x80000000 -+ * IO (domain 2): 0xa0000000 -+ */ -+ writel(0x60000000 + (0x20000000 * pcie->domain), pcie->reg + H2X_REMAP_DIRECT_ADDR); -+ -+ /* Prepare for 64-bit BAR pref */ -+ writel(0x3, pcie->reg + H2X_REMAP_PREF_ADDR); -+ -+ reset_control_deassert(pcie->perst); -+ if (pcie->perst_rc_out) -+ gpiod_set_value(pcie->perst_rc_out, 1); -+ mdelay(1000); -+ -+ pcie->host->ops = &aspeed_ast2700_pcie_ops; -+ -+ if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) { -+ regmap_write_bits(pcie->pciephy, PEHR_MISC_44, ENABLE_SLOT_CAP, -+ ENABLE_SLOT_CAP); -+ regmap_write(pcie->pciephy, PEHR_MISC_3C, -+ HOTPLUG_CAPABLE_ENABLE | HOTPLUG_SURPRISE_ENABLE | -+ ATTENTION_BUTTON_ENABLE); -+ regmap_write_bits(pcie->pciephy, PEHR_MISC_38, -+ DATALINK_REPORT_CAP, DATALINK_REPORT_CAP); -+ } -+ -+ if (!aspeed_ast2700_get_link(pcie)) -+ dev_info(dev, "PCIe Link DOWN"); -+ else -+ dev_info(dev, "PCIe Link UP"); -+ -+ return 0; -+} -+ -+static int aspeed_pcie_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct pci_host_bridge *host; -+ struct aspeed_pcie *pcie; -+ struct device_node *node = dev->of_node; -+ struct resource bus_range; -+ const void *md = of_device_get_match_data(dev); -+ int irq, ret; -+ -+ if (!md) -+ return -ENODEV; -+ -+ host = devm_pci_alloc_host_bridge(dev, sizeof(*pcie)); -+ if (!host) -+ return -ENOMEM; -+ -+ pcie = pci_host_bridge_priv(host); -+ pcie->dev = dev; -+ pcie->tx_tag = 0; -+ platform_set_drvdata(pdev, pcie); -+ -+ pcie->platform = md; -+ pcie->host = host; -+ -+ if (of_pci_parse_bus_range(node, &bus_range)) { -+ dev_warn(dev, "Failed to parse bus range\n"); -+ pcie->host_bus_num = 0; -+ } -+ pcie->host_bus_num = bus_range.start; -+ -+ pcie->reg = devm_platform_ioremap_resource(pdev, 0); -+ -+ pcie->domain = of_get_pci_domain_nr(node); -+ -+ pcie->cfg = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,pciecfg"); -+ if (IS_ERR(pcie->cfg)) -+ return dev_err_probe(dev, PTR_ERR(pcie->cfg), "Failed to map pciecfg base\n"); -+ -+ pcie->pciephy = syscon_regmap_lookup_by_phandle(node, "aspeed,pciephy"); -+ if (IS_ERR(pcie->pciephy)) -+ return dev_err_probe(dev, PTR_ERR(pcie->pciephy), "Failed to map pciephy base\n"); -+ -+ pcie->h2xrst = devm_reset_control_get_exclusive(dev, "h2x"); -+ if (IS_ERR(pcie->h2xrst)) -+ return dev_err_probe(dev, PTR_ERR(pcie->h2xrst), "Failed to get h2x reset\n"); -+ -+ pcie->perst = devm_reset_control_get_exclusive(dev, "perst"); -+ if (IS_ERR(pcie->perst)) -+ return dev_err_probe(dev, PTR_ERR(pcie->perst), "Failed to get perst reset\n"); -+ -+ pcie->perst_rc_out = devm_gpiod_get_optional(dev, "perst-rc-out", -+ GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); -+ -+ ret = devm_mutex_init(dev, &pcie->lock); -+ if (ret) -+ return dev_err_probe(dev, ret, "failed to init mutex\n"); -+ -+ ret = pcie->platform->setup(pdev); -+ if (ret) -+ return dev_err_probe(dev, ret, "Failed to setup PCIe RC\n"); -+ -+ if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) { -+ ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_hotplug.attr); -+ if (ret) -+ return dev_err_probe(&pdev->dev, ret, "unable to create sysfs interface\n"); -+ } -+ -+ host->sysdata = pcie; -+ -+ ret = aspeed_pcie_init_irq_domain(pcie); -+ if (ret) -+ return dev_err_probe(dev, ret, "Failed to initialize IntX/MSI domain\n"); -+ -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) -+ return dev_err_probe(dev, irq, "Failed to get IRQ\n"); -+ -+ ret = devm_request_irq(dev, irq, aspeed_pcie_intr_handler, IRQF_SHARED, -+ dev_name(dev), pcie); -+ if (ret) -+ return dev_err_probe(dev, ret, "Failed to request IRQ\n"); -+ -+ pcie->clock = clk_get(dev, NULL); -+ if (IS_ERR(pcie->clock)) -+ return dev_err_probe(dev, PTR_ERR(pcie->clock), "Failed to request clock\n"); -+ -+ ret = clk_prepare_enable(pcie->clock); -+ if (ret) { -+ clk_put(pcie->clock); -+ return dev_err_probe(dev, ret, "Failed to enable the clock\n"); -+ } -+ -+ return pci_host_probe(host); -+} -+ -+static void aspeed_pcie_remove(struct platform_device *pdev) -+{ -+ struct aspeed_pcie *pcie = platform_get_drvdata(pdev); -+ -+ if (pcie->clock) { -+ clk_disable_unprepare(pcie->clock); -+ clk_put(pcie->clock); -+ } -+ -+ pci_stop_root_bus(pcie->host->bus); -+ pci_remove_root_bus(pcie->host->bus); -+ aspeed_pcie_irq_domain_free(pcie); -+} -+ -+static struct aspeed_pcie_rc_platform pcie_rc_ast2600 = { -+ .setup = aspeed_ast2600_setup, -+ .reg_intx_en = 0x04, -+ .reg_intx_sts = 0x08, -+ .reg_msi_en = 0x20, -+ .reg_msi_sts = 0x28, -+ .msi_support = false, -+ .msi_address = 0x1e77005c, -+}; -+ -+static struct aspeed_pcie_rc_platform pcie_rc_ast2700 = { -+ .setup = aspeed_ast2700_setup, -+ .reg_intx_en = 0x40, -+ .reg_intx_sts = 0x48, -+ .reg_msi_en = 0x50, -+ .reg_msi_sts = 0x58, -+ .msi_support = true, -+ .msi_address = 0x000000f0, -+}; -+ -+static const struct of_device_id aspeed_pcie_of_match[] = { -+ { .compatible = "aspeed,ast2600-pcie", .data = &pcie_rc_ast2600 }, -+ { .compatible = "aspeed,ast2700-pcie", .data = &pcie_rc_ast2700 }, -+ {} -+}; -+ -+static struct platform_driver aspeed_pcie_driver = { -+ .driver = { -+ .name = "aspeed-pcie", -+ .suppress_bind_attrs = true, -+ .of_match_table = aspeed_pcie_of_match, -+ }, -+ .probe = aspeed_pcie_probe, -+ .remove_new = aspeed_pcie_remove, -+}; -+ -+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 2026-04-08 18:03:34.885950437 +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 2026-04-08 18:03:39.794860903 +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 2026-04-08 18:03:46.226743396 +0000 -@@ -0,0 +1,23 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+ -+# -+# PHY drivers for ASPEED -+# -+ -+config PHY_ASPEED_SGMII -+ tristate "ASPEED SGMII PHY driver" -+ select REGMAP -+ select MFD_SYSCON -+ select GENERIC_PHY -+ depends on ARCH_ASPEED -+ default n -+ help -+ Enable driver support for Aspeed AST2700 PHY SGMII. -+ -+config PHY_ASPEED_USB3 -+ tristate "ASPEED USB3 PHY driver" -+ select GENERIC_PHY -+ depends on ARCH_ASPEED -+ default n -+ help -+ Enable driver support for Aspeed AST2700 PHY USB3. -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 2026-04-08 18:03:46.226743396 +0000 -@@ -0,0 +1,4 @@ -+# SPDX-License-Identifier: GPL-2.0 -+ -+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-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 2026-04-08 18:03:48.216707037 +0000 -@@ -0,0 +1,257 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright 2023 Aspeed Technology Inc. -+ */ -+ -+#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; -+ 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 -+ }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, aspeed_usb_phy3_dt_ids); -+ -+static int aspeed_usb_phy3_init(struct phy *phy) -+{ -+ struct aspeed_usb_phy3 *phy3 = phy_get_drvdata(phy); -+ const struct aspeed_usb_phy3_model *model = phy3->model; -+ u32 val; -+ int timeout = 100; -+ int i, j; -+ -+ 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; -+ } -+ } -+ -+ val = readl(phy3->regs + model->phy3s00); -+ -+ if (phy3->phy_ext_load_quirk) -+ val |= USB_PHY3_SRAM_EXT_LOAD; -+ else -+ val |= USB_PHY3_SRAM_BYPASS; -+ writel(val, phy3->regs + model->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(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; -+ -+ val = (ctrl_data[i].offset << 16) | (ctrl_data[i].value >> 16); -+ writel(val, phy3->regs + j); -+ j += 4; -+ } -+ } -+ -+ dev_info(phy3->dev, "Initialized USB PHY3\n"); -+ return 0; -+} -+ -+static const struct phy_ops aspeed_usb_phy3_phyops = { -+ .init = aspeed_usb_phy3_init, -+ .owner = THIS_MODULE, -+}; -+ -+static int aspeed_usb_phy3_probe(struct platform_device *pdev) -+{ -+ struct aspeed_usb_phy3 *phy3; -+ struct device *dev; -+ struct phy_provider *provider; -+ 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) -+ 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; -+ } -+ -+ 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; -+ -+ phy3->regs = of_iomap(node, 0); -+ -+ phy3->phy_ext_load_quirk = -+ device_property_read_bool(dev, "aspeed,phy_ext_load_quirk"); -+ -+ phy = devm_phy_create(dev, NULL, &aspeed_usb_phy3_phyops); -+ if (IS_ERR(phy)) { -+ dev_err(dev, "failed to create PHY\n"); -+ 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); -+ -+ dev_info(phy3->dev, "Probed USB PHY3\n"); -+ -+ return 0; -+ -+err: -+ if (clk) -+ clk_disable_unprepare(clk); -+ return rc; -+} -+ -+static void aspeed_usb_phy3_remove(struct platform_device *pdev) -+{ -+} -+ -+static struct platform_driver aspeed_usb_phy3_driver = { -+ .probe = aspeed_usb_phy3_probe, -+ .remove = aspeed_usb_phy3_remove, -+ .driver = { -+ .name = KBUILD_MODNAME, -+ .of_match_table = aspeed_usb_phy3_dt_ids, -+ }, -+}; -+module_platform_driver(aspeed_usb_phy3_driver); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Joe Wang "); -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-04-08 18:03:48.211707129 +0000 -@@ -0,0 +1,234 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright 2023 Aspeed Technology Inc. -+ */ -+#include -+#include -+#include -+#include -+#include -+#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 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 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 *pcie_phy_regmap; -+ u8 revision; -+}; -+ -+static int aspeed_sgmii_conf(struct phy *phy, bool nway, int speed) -+{ -+ struct aspeed_sgmii *sgmii = phy_get_drvdata(phy); -+ u32 cfg; -+ -+ writel(0, sgmii->regs + SGMII_MODE); -+ -+ writel(0, sgmii->regs + SGMII_CFG); -+ 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 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); -+ -+ 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) -+{ -+ /* Default to enable Nway, not need configure speed */ -+ return aspeed_sgmii_conf(phy, true, 0); -+} -+ -+static int aspeed_sgmii_phy_set_speed(struct phy *phy, int speed) -+{ -+ return aspeed_sgmii_conf(phy, false, speed); -+} -+ -+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); -+ -+ return 0; -+} -+ -+static const struct phy_ops aspeed_sgmii_phyops = { -+ .init = aspeed_sgmii_phy_init, -+ .set_speed = aspeed_sgmii_phy_set_speed, -+ .exit = aspeed_sgmii_phy_exit, -+ .owner = THIS_MODULE, -+}; -+ -+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 phy *phy; -+ u32 reg; -+ -+ dev = &pdev->dev; -+ -+ sgmii = devm_kzalloc(dev, sizeof(*sgmii), GFP_KERNEL); -+ if (!sgmii) -+ return -ENOMEM; -+ -+ sgmii->dev = dev; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) { -+ dev_err(dev, "cannot get resource\n"); -+ return -ENODEV; -+ } -+ -+ sgmii->regs = devm_ioremap_resource(dev, res); -+ if (IS_ERR(sgmii->regs)) { -+ dev_err(dev, "cannot map registers\n"); -+ return PTR_ERR(sgmii->regs); -+ } -+ -+ np = pdev->dev.of_node; -+ 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"); -+ 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, 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; -+} -+ -+static const struct of_device_id aspeed_sgmii_of_matches[] = { -+ { .compatible = "aspeed,ast2700-sgmii" }, -+ { }, -+}; -+ -+static struct platform_driver aspeed_sgmii_driver = { -+ .probe = aspeed_sgmii_probe, -+ .driver = { -+ .name = "aspeed-sgmii", -+ .of_match_table = aspeed_sgmii_of_matches, -+ }, -+}; -+ -+module_platform_driver(aspeed_sgmii_driver); -+ -+MODULE_AUTHOR("Jacky Chou "); -+MODULE_DESCRIPTION("ASPEED SGMII Serdes/PHY controller"); -+MODULE_LICENSE("GPL"); -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 2026-04-08 18:03:48.322705101 +0000 -@@ -31,3 +31,11 @@ - help - Say Y here to enable pin controller support for Aspeed's 6th - generation SoCs. GPIO is provided by a separate GPIO driver. -+ -+config PINCTRL_ASPEED_G7 -+ bool "Aspeed G7 SoC pin control" -+ depends on (ARCH_ASPEED || COMPILE_TEST) && OF -+ select PINCTRL_ASPEED -+ help -+ 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 2026-04-08 18:03:48.322705101 +0000 -@@ -6,3 +6,4 @@ - obj-$(CONFIG_PINCTRL_ASPEED_G4) += pinctrl-aspeed-g4.o - obj-$(CONFIG_PINCTRL_ASPEED_G5) += pinctrl-aspeed-g5.o - obj-$(CONFIG_PINCTRL_ASPEED_G6) += pinctrl-aspeed-g6.o -+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 2026-04-08 18:03:48.322705101 +0000 -@@ -17,6 +17,8 @@ - #include "../pinctrl-utils.h" - #include "pinctrl-aspeed.h" - -+#define SCU040 0x040 /* Reset Control Set 1 */ -+#define SCU0C8 0x0C8 /* Debug Control */ - #define SCU400 0x400 /* Multi-function Pin Control #1 */ - #define SCU404 0x404 /* Multi-function Pin Control #2 */ - #define SCU40C 0x40C /* Multi-function Pin Control #3 */ -@@ -31,6 +33,7 @@ - #define SCU450 0x450 /* Multi-function Pin Control #14 */ - #define SCU454 0x454 /* Multi-function Pin Control #15 */ - #define SCU458 0x458 /* Multi-function Pin Control #16 */ -+#define SCU470 0x470 - #define SCU4B0 0x4B0 /* Multi-function Pin Control #17 */ - #define SCU4B4 0x4B4 /* Multi-function Pin Control #18 */ - #define SCU4B8 0x4B8 /* Multi-function Pin Control #19 */ -@@ -46,13 +49,16 @@ - #define SCU630 0x630 /* Disable GPIO Internal Pull-Down #4 */ - #define SCU634 0x634 /* Disable GPIO Internal Pull-Down #5 */ - #define SCU638 0x638 /* Disable GPIO Internal Pull-Down #6 */ -+#define SCU650 0x650 /* Driving Strength */ - #define SCU690 0x690 /* Multi-function Pin Control #24 */ - #define SCU694 0x694 /* Multi-function Pin Control #25 */ -+#define SCU698 0x698 /* Multi-function Pin Control #26 */ - #define SCU69C 0x69C /* Multi-function Pin Control #27 */ - #define SCU6D0 0x6D0 /* Multi-function Pin Control #29 */ - #define SCUC20 0xC20 /* PCIE configuration Setting Control */ -+#define SCUC24 0xC24 /* BMC MMIO Decode Setting */ - --#define ASPEED_G6_NR_PINS 256 -+#define ASPEED_G6_NR_PINS 258 - - #define M24 0 - SIG_EXPR_LIST_DECL_SESG(M24, MDC3, MDIO3, SIG_DESC_SET(SCU410, 0)); -@@ -171,81 +177,93 @@ - - #define H24 16 - SIG_EXPR_LIST_DECL_SESG(H24, RGMII3TXCK, RGMII3, SIG_DESC_SET(SCU410, 16), -- SIG_DESC_SET(SCU510, 0)); -+ SIG_DESC_SET(SCU510, 0)); - SIG_EXPR_LIST_DECL_SESG(H24, RMII3RCLKO, RMII3, SIG_DESC_SET(SCU410, 16), -- SIG_DESC_CLEAR(SCU510, 0)); --PIN_DECL_2(H24, GPIOC0, RGMII3TXCK, RMII3RCLKO); -+ SIG_DESC_CLEAR(SCU510, 0)); -+SIG_EXPR_LIST_DECL_SESG(H24, VPA_B0, VPA, SIG_DESC_CLEAR(SCU410, 16)); -+PIN_DECL_3(H24, GPIOC0, RGMII3TXCK, RMII3RCLKO, VPA_B0); - - #define J22 17 - SIG_EXPR_LIST_DECL_SESG(J22, RGMII3TXCTL, RGMII3, SIG_DESC_SET(SCU410, 17), -- SIG_DESC_SET(SCU510, 0)); -+ SIG_DESC_SET(SCU510, 0)); - SIG_EXPR_LIST_DECL_SESG(J22, RMII3TXEN, RMII3, SIG_DESC_SET(SCU410, 17), -- SIG_DESC_CLEAR(SCU510, 0)); --PIN_DECL_2(J22, GPIOC1, RGMII3TXCTL, RMII3TXEN); -+ SIG_DESC_CLEAR(SCU510, 0)); -+SIG_EXPR_LIST_DECL_SESG(J22, VPA_B1, VPA, SIG_DESC_CLEAR(SCU410, 17)); -+PIN_DECL_3(J22, GPIOC1, RGMII3TXCTL, RMII3TXEN, VPA_B1); - - #define H22 18 - SIG_EXPR_LIST_DECL_SESG(H22, RGMII3TXD0, RGMII3, SIG_DESC_SET(SCU410, 18), -- SIG_DESC_SET(SCU510, 0)); -+ SIG_DESC_SET(SCU510, 0)); - SIG_EXPR_LIST_DECL_SESG(H22, RMII3TXD0, RMII3, SIG_DESC_SET(SCU410, 18), -- SIG_DESC_CLEAR(SCU510, 0)); --PIN_DECL_2(H22, GPIOC2, RGMII3TXD0, RMII3TXD0); -+ SIG_DESC_CLEAR(SCU510, 0)); -+SIG_EXPR_LIST_DECL_SESG(H22, VPA_B2, VPA, SIG_DESC_CLEAR(SCU410, 18)); -+PIN_DECL_3(H22, GPIOC2, RGMII3TXD0, RMII3TXD0, VPA_B2); - - #define H23 19 - SIG_EXPR_LIST_DECL_SESG(H23, RGMII3TXD1, RGMII3, SIG_DESC_SET(SCU410, 19), -- SIG_DESC_SET(SCU510, 0)); -+ SIG_DESC_SET(SCU510, 0)); - SIG_EXPR_LIST_DECL_SESG(H23, RMII3TXD1, RMII3, SIG_DESC_SET(SCU410, 19), -- SIG_DESC_CLEAR(SCU510, 0)); --PIN_DECL_2(H23, GPIOC3, RGMII3TXD1, RMII3TXD1); -+ SIG_DESC_CLEAR(SCU510, 0)); -+SIG_EXPR_LIST_DECL_SESG(H23, VPA_B3, VPA, SIG_DESC_CLEAR(SCU410, 19)); -+PIN_DECL_3(H23, GPIOC3, RGMII3TXD1, RMII3TXD1, VPA_B3); - - #define G22 20 - SIG_EXPR_LIST_DECL_SESG(G22, RGMII3TXD2, RGMII3, SIG_DESC_SET(SCU410, 20), -- SIG_DESC_SET(SCU510, 0)); --PIN_DECL_1(G22, GPIOC4, RGMII3TXD2); -+ SIG_DESC_SET(SCU510, 0)); -+SIG_EXPR_LIST_DECL_SESG(G22, VPA_B4, VPA, SIG_DESC_CLEAR(SCU410, 20)); -+PIN_DECL_2(G22, GPIOC4, RGMII3TXD2, VPA_B4); - - #define F22 21 - SIG_EXPR_LIST_DECL_SESG(F22, RGMII3TXD3, RGMII3, SIG_DESC_SET(SCU410, 21), -- SIG_DESC_SET(SCU510, 0)); --PIN_DECL_1(F22, GPIOC5, RGMII3TXD3); -+ SIG_DESC_SET(SCU510, 0)); -+SIG_EXPR_LIST_DECL_SESG(F22, VPA_B5, VPA, SIG_DESC_CLEAR(SCU410, 21)); -+PIN_DECL_2(F22, GPIOC5, RGMII3TXD3, VPA_B5); - - #define G23 22 - SIG_EXPR_LIST_DECL_SESG(G23, RGMII3RXCK, RGMII3, SIG_DESC_SET(SCU410, 22), -- SIG_DESC_SET(SCU510, 0)); -+ SIG_DESC_SET(SCU510, 0)); - SIG_EXPR_LIST_DECL_SESG(G23, RMII3RCLKI, RMII3, SIG_DESC_SET(SCU410, 22), -- SIG_DESC_CLEAR(SCU510, 0)); --PIN_DECL_2(G23, GPIOC6, RGMII3RXCK, RMII3RCLKI); -+ SIG_DESC_CLEAR(SCU510, 0)); -+SIG_EXPR_LIST_DECL_SESG(G23, VPAPCLK, VPA, SIG_DESC_CLEAR(SCU410, 22)); -+PIN_DECL_3(G23, GPIOC6, RGMII3RXCK, RMII3RCLKI, VPAPCLK); - - #define G24 23 - SIG_EXPR_LIST_DECL_SESG(G24, RGMII3RXCTL, RGMII3, SIG_DESC_SET(SCU410, 23), -- SIG_DESC_SET(SCU510, 0)); --PIN_DECL_1(G24, GPIOC7, RGMII3RXCTL); -+ SIG_DESC_SET(SCU510, 0)); -+SIG_EXPR_LIST_DECL_SESG(G24, VPA_B6, VPA, SIG_DESC_CLEAR(SCU410, 23)); -+PIN_DECL_2(G24, GPIOC7, RGMII3RXCTL, VPA_B6); - - #define F23 24 - SIG_EXPR_LIST_DECL_SESG(F23, RGMII3RXD0, RGMII3, SIG_DESC_SET(SCU410, 24), -- SIG_DESC_SET(SCU510, 0)); -+ SIG_DESC_SET(SCU510, 0)); - SIG_EXPR_LIST_DECL_SESG(F23, RMII3RXD0, RMII3, SIG_DESC_SET(SCU410, 24), -- SIG_DESC_CLEAR(SCU510, 0)); --PIN_DECL_2(F23, GPIOD0, RGMII3RXD0, RMII3RXD0); -+ SIG_DESC_CLEAR(SCU510, 0)); -+SIG_EXPR_LIST_DECL_SESG(F23, VPA_B7, VPA, SIG_DESC_CLEAR(SCU410, 24)); -+PIN_DECL_3(F23, GPIOD0, RGMII3RXD0, RMII3RXD0, VPA_B7); - - #define F26 25 - SIG_EXPR_LIST_DECL_SESG(F26, RGMII3RXD1, RGMII3, SIG_DESC_SET(SCU410, 25), -- SIG_DESC_SET(SCU510, 0)); -+ SIG_DESC_SET(SCU510, 0)); - SIG_EXPR_LIST_DECL_SESG(F26, RMII3RXD1, RMII3, SIG_DESC_SET(SCU410, 25), -- SIG_DESC_CLEAR(SCU510, 0)); --PIN_DECL_2(F26, GPIOD1, RGMII3RXD1, RMII3RXD1); -+ SIG_DESC_CLEAR(SCU510, 0)); -+SIG_EXPR_LIST_DECL_SESG(F26, VPA_G0, VPA, SIG_DESC_CLEAR(SCU410, 25)); -+PIN_DECL_3(F26, GPIOD1, RGMII3RXD1, RMII3RXD1, VPA_G0); - - #define F25 26 - SIG_EXPR_LIST_DECL_SESG(F25, RGMII3RXD2, RGMII3, SIG_DESC_SET(SCU410, 26), -- SIG_DESC_SET(SCU510, 0)); -+ SIG_DESC_SET(SCU510, 0)); - SIG_EXPR_LIST_DECL_SESG(F25, RMII3CRSDV, RMII3, SIG_DESC_SET(SCU410, 26), -- SIG_DESC_CLEAR(SCU510, 0)); --PIN_DECL_2(F25, GPIOD2, RGMII3RXD2, RMII3CRSDV); -+ SIG_DESC_CLEAR(SCU510, 0)); -+SIG_EXPR_LIST_DECL_SESG(F25, VPA_G1, VPA, SIG_DESC_CLEAR(SCU410, 26)); -+PIN_DECL_3(F25, GPIOD2, RGMII3RXD2, RMII3CRSDV, VPA_G1); - - #define E26 27 - SIG_EXPR_LIST_DECL_SESG(E26, RGMII3RXD3, RGMII3, SIG_DESC_SET(SCU410, 27), -- SIG_DESC_SET(SCU510, 0)); -+ SIG_DESC_SET(SCU510, 0)); - SIG_EXPR_LIST_DECL_SESG(E26, RMII3RXER, RMII3, SIG_DESC_SET(SCU410, 27), -- SIG_DESC_CLEAR(SCU510, 0)); --PIN_DECL_2(E26, GPIOD3, RGMII3RXD3, RMII3RXER); -+ SIG_DESC_CLEAR(SCU510, 0)); -+SIG_EXPR_LIST_DECL_SESG(E26, VPA_G2, VPA, SIG_DESC_CLEAR(SCU410, 27)); -+PIN_DECL_3(E26, GPIOD3, RGMII3RXD3, RMII3RXER, VPA_G2); - - FUNC_GROUP_DECL(RGMII3, H24, J22, H22, H23, G22, F22, G23, G24, F23, F26, F25, - E26); -@@ -259,7 +277,9 @@ - SIG_DESC_SET(SCU510, 1)); - SIG_EXPR_LIST_DECL_SESG(F24, RMII4RCLKO, RMII4, SIG_DESC_SET(SCU4B0, 28), - SIG_DESC_CLEAR(SCU510, 1)); --PIN_DECL_3(F24, GPIOD4, NCTS3, RGMII4TXCK, RMII4RCLKO); -+SIG_EXPR_LIST_DECL_SESG(F24, VPA_G3, VPA, SIG_DESC_CLEAR(SCU410, 28), -+ SIG_DESC_CLEAR(SCU4B0, 28)); -+PIN_DECL_4(F24, GPIOD4, NCTS3, RGMII4TXCK, RMII4RCLKO, VPA_G3); - FUNC_GROUP_DECL(NCTS3, F24); - - #define E23 29 -@@ -268,7 +288,9 @@ - SIG_DESC_SET(SCU510, 1)); - SIG_EXPR_LIST_DECL_SESG(E23, RMII4TXEN, RMII4, SIG_DESC_SET(SCU4B0, 29), - SIG_DESC_CLEAR(SCU510, 1)); --PIN_DECL_3(E23, GPIOD5, NDCD3, RGMII4TXCTL, RMII4TXEN); -+SIG_EXPR_LIST_DECL_SESG(E23, VPA_G4, VPA, SIG_DESC_CLEAR(SCU410, 29), -+ SIG_DESC_CLEAR(SCU4B0, 29)); -+PIN_DECL_4(E23, GPIOD5, NDCD3, RGMII4TXCTL, RMII4TXEN, VPA_G4); - FUNC_GROUP_DECL(NDCD3, E23); - - #define E24 30 -@@ -277,7 +299,9 @@ - SIG_DESC_SET(SCU510, 1)); - SIG_EXPR_LIST_DECL_SESG(E24, RMII4TXD0, RMII4, SIG_DESC_SET(SCU4B0, 30), - SIG_DESC_CLEAR(SCU510, 1)); --PIN_DECL_3(E24, GPIOD6, NDSR3, RGMII4TXD0, RMII4TXD0); -+SIG_EXPR_LIST_DECL_SESG(E24, VPA_G5, VPA, SIG_DESC_CLEAR(SCU410, 30), -+ SIG_DESC_CLEAR(SCU4B0, 30)); -+PIN_DECL_4(E24, GPIOD6, NDSR3, RGMII4TXD0, RMII4TXD0, VPA_G5); - FUNC_GROUP_DECL(NDSR3, E24); - - #define E25 31 -@@ -286,73 +310,99 @@ - SIG_DESC_SET(SCU510, 1)); - SIG_EXPR_LIST_DECL_SESG(E25, RMII4TXD1, RMII4, SIG_DESC_SET(SCU4B0, 31), - SIG_DESC_CLEAR(SCU510, 1)); --PIN_DECL_3(E25, GPIOD7, NRI3, RGMII4TXD1, RMII4TXD1); -+SIG_EXPR_LIST_DECL_SESG(E25, VPA_G6, VPA, SIG_DESC_CLEAR(SCU410, 31), -+ SIG_DESC_CLEAR(SCU4B0, 31)); -+PIN_DECL_4(E25, GPIOD7, NRI3, RGMII4TXD1, RMII4TXD1, VPA_G6); - FUNC_GROUP_DECL(NRI3, E25); - - #define D26 32 --SIG_EXPR_LIST_DECL_SESG(D26, NDTR3, NDTR3, SIG_DESC_SET(SCU414, 0)); -+SIG_EXPR_LIST_DECL_SESG(D26, NDTR3, NDTR3, SIG_DESC_SET(SCU414, 0), -+ SIG_DESC_CLEAR(SCU470, 16)); - SIG_EXPR_LIST_DECL_SESG(D26, RGMII4TXD2, RGMII4, SIG_DESC_SET(SCU4B4, 0), -- SIG_DESC_SET(SCU510, 1)); --PIN_DECL_2(D26, GPIOE0, NDTR3, RGMII4TXD2); -+ SIG_DESC_CLEAR(SCU470, 16), SIG_DESC_SET(SCU510, 1)); -+SIG_EXPR_LIST_DECL_SESG(D26, VPA_G7, VPA, SIG_DESC_CLEAR(SCU414, 0), -+ SIG_DESC_CLEAR(SCU4B4, 0)); -+PIN_DECL_3(D26, GPIOE0, NDTR3, RGMII4TXD2, VPA_G7); - FUNC_GROUP_DECL(NDTR3, D26); - - #define D24 33 --SIG_EXPR_LIST_DECL_SESG(D24, NRTS3, NRTS3, SIG_DESC_SET(SCU414, 1)); -+SIG_EXPR_LIST_DECL_SESG(D24, NRTS3, NRTS3, SIG_DESC_SET(SCU414, 1), -+ SIG_DESC_CLEAR(SCU470, 17)); - SIG_EXPR_LIST_DECL_SESG(D24, RGMII4TXD3, RGMII4, SIG_DESC_SET(SCU4B4, 1), -- SIG_DESC_SET(SCU510, 1)); --PIN_DECL_2(D24, GPIOE1, NRTS3, RGMII4TXD3); -+ SIG_DESC_CLEAR(SCU470, 17), SIG_DESC_SET(SCU510, 1)); -+SIG_EXPR_LIST_DECL_SESG(D24, VPA_R0, VPA, SIG_DESC_CLEAR(SCU414, 1), -+ SIG_DESC_CLEAR(SCU4B4, 1)); -+PIN_DECL_3(D24, GPIOE1, NRTS3, RGMII4TXD3, VPA_R0); - FUNC_GROUP_DECL(NRTS3, D24); - - #define C25 34 --SIG_EXPR_LIST_DECL_SESG(C25, NCTS4, NCTS4, SIG_DESC_SET(SCU414, 2)); -+SIG_EXPR_LIST_DECL_SESG(C25, NCTS4, NCTS4, SIG_DESC_SET(SCU414, 2), -+ SIG_DESC_CLEAR(SCU470, 18)); - SIG_EXPR_LIST_DECL_SESG(C25, RGMII4RXCK, RGMII4, SIG_DESC_SET(SCU4B4, 2), -- SIG_DESC_SET(SCU510, 1)); -+ SIG_DESC_CLEAR(SCU470, 18), SIG_DESC_SET(SCU510, 1)); - SIG_EXPR_LIST_DECL_SESG(C25, RMII4RCLKI, RMII4, SIG_DESC_SET(SCU4B4, 2), -- SIG_DESC_CLEAR(SCU510, 1)); --PIN_DECL_3(C25, GPIOE2, NCTS4, RGMII4RXCK, RMII4RCLKI); -+ SIG_DESC_CLEAR(SCU470, 18), SIG_DESC_CLEAR(SCU510, 1)); -+SIG_EXPR_LIST_DECL_SESG(C25, VPA_R1, VPA, SIG_DESC_CLEAR(SCU414, 2), -+ SIG_DESC_CLEAR(SCU4B4, 2)); -+PIN_DECL_4(C25, GPIOE2, NCTS4, RGMII4RXCK, RMII4RCLKI, VPA_R1); - FUNC_GROUP_DECL(NCTS4, C25); - - #define C26 35 --SIG_EXPR_LIST_DECL_SESG(C26, NDCD4, NDCD4, SIG_DESC_SET(SCU414, 3)); -+SIG_EXPR_LIST_DECL_SESG(C26, NDCD4, NDCD4, SIG_DESC_SET(SCU414, 3), -+ SIG_DESC_CLEAR(SCU470, 19)); - SIG_EXPR_LIST_DECL_SESG(C26, RGMII4RXCTL, RGMII4, SIG_DESC_SET(SCU4B4, 3), -- SIG_DESC_SET(SCU510, 1)); --PIN_DECL_2(C26, GPIOE3, NDCD4, RGMII4RXCTL); -+ SIG_DESC_CLEAR(SCU470, 19), SIG_DESC_SET(SCU510, 1)); -+SIG_EXPR_LIST_DECL_SESG(C26, VPA_R2, VPA, SIG_DESC_CLEAR(SCU414, 3), -+ SIG_DESC_CLEAR(SCU4B4, 3)); -+PIN_DECL_3(C26, GPIOE3, NDCD4, RGMII4RXCTL, VPA_R2); - FUNC_GROUP_DECL(NDCD4, C26); - - #define C24 36 --SIG_EXPR_LIST_DECL_SESG(C24, NDSR4, NDSR4, SIG_DESC_SET(SCU414, 4)); -+SIG_EXPR_LIST_DECL_SESG(C24, NDSR4, NDSR4, SIG_DESC_SET(SCU414, 4), -+ SIG_DESC_CLEAR(SCU470, 20)); - SIG_EXPR_LIST_DECL_SESG(C24, RGMII4RXD0, RGMII4, SIG_DESC_SET(SCU4B4, 4), -- SIG_DESC_SET(SCU510, 1)); -+ SIG_DESC_CLEAR(SCU470, 20), SIG_DESC_SET(SCU510, 1)); - SIG_EXPR_LIST_DECL_SESG(C24, RMII4RXD0, RMII4, SIG_DESC_SET(SCU4B4, 4), -- SIG_DESC_CLEAR(SCU510, 1)); --PIN_DECL_3(C24, GPIOE4, NDSR4, RGMII4RXD0, RMII4RXD0); -+ SIG_DESC_CLEAR(SCU470, 20), SIG_DESC_CLEAR(SCU510, 1)); -+SIG_EXPR_LIST_DECL_SESG(C24, VPA_R3, VPA, SIG_DESC_CLEAR(SCU414, 4), -+ SIG_DESC_CLEAR(SCU4B4, 4)); -+PIN_DECL_4(C24, GPIOE4, NDSR4, RGMII4RXD0, RMII4RXD0, VPA_R3); - FUNC_GROUP_DECL(NDSR4, C24); - - #define B26 37 --SIG_EXPR_LIST_DECL_SESG(B26, NRI4, NRI4, SIG_DESC_SET(SCU414, 5)); -+SIG_EXPR_LIST_DECL_SESG(B26, NRI4, NRI4, SIG_DESC_SET(SCU414, 5), -+ SIG_DESC_CLEAR(SCU470, 21)); - SIG_EXPR_LIST_DECL_SESG(B26, RGMII4RXD1, RGMII4, SIG_DESC_SET(SCU4B4, 5), -- SIG_DESC_SET(SCU510, 1)); -+ SIG_DESC_CLEAR(SCU470, 21), SIG_DESC_SET(SCU510, 1)); - SIG_EXPR_LIST_DECL_SESG(B26, RMII4RXD1, RMII4, SIG_DESC_SET(SCU4B4, 5), -- SIG_DESC_CLEAR(SCU510, 1)); --PIN_DECL_3(B26, GPIOE5, NRI4, RGMII4RXD1, RMII4RXD1); -+ SIG_DESC_CLEAR(SCU470, 21), SIG_DESC_CLEAR(SCU510, 1)); -+SIG_EXPR_LIST_DECL_SESG(B26, VPA_R4, VPA, SIG_DESC_CLEAR(SCU414, 5), -+ SIG_DESC_CLEAR(SCU4B4, 5)); -+PIN_DECL_4(B26, GPIOE5, NRI4, RGMII4RXD1, RMII4RXD1, VPA_R4); - FUNC_GROUP_DECL(NRI4, B26); - - #define B25 38 --SIG_EXPR_LIST_DECL_SESG(B25, NDTR4, NDTR4, SIG_DESC_SET(SCU414, 6)); -+SIG_EXPR_LIST_DECL_SESG(B25, NDTR4, NDTR4, SIG_DESC_SET(SCU414, 6), -+ SIG_DESC_CLEAR(SCU470, 22)); - SIG_EXPR_LIST_DECL_SESG(B25, RGMII4RXD2, RGMII4, SIG_DESC_SET(SCU4B4, 6), -- SIG_DESC_SET(SCU510, 1)); -+ SIG_DESC_CLEAR(SCU470, 22), SIG_DESC_SET(SCU510, 1)); - SIG_EXPR_LIST_DECL_SESG(B25, RMII4CRSDV, RMII4, SIG_DESC_SET(SCU4B4, 6), -- SIG_DESC_CLEAR(SCU510, 1)); --PIN_DECL_3(B25, GPIOE6, NDTR4, RGMII4RXD2, RMII4CRSDV); -+ SIG_DESC_CLEAR(SCU470, 22), SIG_DESC_CLEAR(SCU510, 1)); -+SIG_EXPR_LIST_DECL_SESG(B25, VPA_R5, VPA, SIG_DESC_CLEAR(SCU414, 6), -+ SIG_DESC_CLEAR(SCU4B4, 6)); -+PIN_DECL_4(B25, GPIOE6, NDTR4, RGMII4RXD2, RMII4CRSDV, VPA_R5); - FUNC_GROUP_DECL(NDTR4, B25); - - #define B24 39 --SIG_EXPR_LIST_DECL_SESG(B24, NRTS4, NRTS4, SIG_DESC_SET(SCU414, 7)); -+SIG_EXPR_LIST_DECL_SESG(B24, NRTS4, NRTS4, SIG_DESC_SET(SCU414, 7), -+ SIG_DESC_CLEAR(SCU470, 23)); - SIG_EXPR_LIST_DECL_SESG(B24, RGMII4RXD3, RGMII4, SIG_DESC_SET(SCU4B4, 7), -- SIG_DESC_SET(SCU510, 1)); -+ SIG_DESC_CLEAR(SCU470, 23), SIG_DESC_SET(SCU510, 1)); - SIG_EXPR_LIST_DECL_SESG(B24, RMII4RXER, RMII4, SIG_DESC_SET(SCU4B4, 7), -- SIG_DESC_CLEAR(SCU510, 1)); --PIN_DECL_3(B24, GPIOE7, NRTS4, RGMII4RXD3, RMII4RXER); -+ SIG_DESC_CLEAR(SCU470, 23), SIG_DESC_CLEAR(SCU510, 1)); -+SIG_EXPR_LIST_DECL_SESG(B24, VPA_R6, VPA, SIG_DESC_CLEAR(SCU414, 7), -+ SIG_DESC_CLEAR(SCU4B4, 7)); -+PIN_DECL_4(B24, GPIOE7, NRTS4, RGMII4RXD3, RMII4RXER, VPA_R6); - FUNC_GROUP_DECL(NRTS4, B24); - - FUNC_GROUP_DECL(RGMII4, F24, E23, E24, E25, D26, D24, C25, C26, C24, B26, B25, -@@ -364,27 +414,39 @@ - #define D22 40 - SIG_EXPR_LIST_DECL_SESG(D22, SD1CLK, SD1, SIG_DESC_SET(SCU414, 8)); - SIG_EXPR_LIST_DECL_SEMG(D22, PWM8, PWM8G0, PWM8, SIG_DESC_SET(SCU4B4, 8)); --PIN_DECL_2(D22, GPIOF0, SD1CLK, PWM8); -+SIG_EXPR_LIST_DECL_SESG(D22, VPA_R7, VPA, SIG_DESC_CLEAR(SCU414, 8), -+ SIG_DESC_CLEAR(SCU4B4, 8)); -+PIN_DECL_3(D22, GPIOF0, SD1CLK, PWM8, VPA_R7); - GROUP_DECL(PWM8G0, D22); - - #define E22 41 - SIG_EXPR_LIST_DECL_SESG(E22, SD1CMD, SD1, SIG_DESC_SET(SCU414, 9)); - SIG_EXPR_LIST_DECL_SEMG(E22, PWM9, PWM9G0, PWM9, SIG_DESC_SET(SCU4B4, 9)); --PIN_DECL_2(E22, GPIOF1, SD1CMD, PWM9); -+SIG_EXPR_LIST_DECL_SESG(E22, VPAHS, VPA, SIG_DESC_CLEAR(SCU414, 9), -+ SIG_DESC_CLEAR(SCU4B4, 9)); -+PIN_DECL_3(E22, GPIOF1, SD1CMD, PWM9, VPAHS); - GROUP_DECL(PWM9G0, E22); - - #define D23 42 - SIG_EXPR_LIST_DECL_SESG(D23, SD1DAT0, SD1, SIG_DESC_SET(SCU414, 10)); - SIG_EXPR_LIST_DECL_SEMG(D23, PWM10, PWM10G0, PWM10, SIG_DESC_SET(SCU4B4, 10)); --PIN_DECL_2(D23, GPIOF2, SD1DAT0, PWM10); -+SIG_EXPR_LIST_DECL_SESG(D23, VPAVS, VPA, SIG_DESC_CLEAR(SCU414, 10), -+ SIG_DESC_CLEAR(SCU4B4, 10)); -+PIN_DECL_3(D23, GPIOF2, SD1DAT0, PWM10, VPAVS); - GROUP_DECL(PWM10G0, D23); - - #define C23 43 - SIG_EXPR_LIST_DECL_SESG(C23, SD1DAT1, SD1, SIG_DESC_SET(SCU414, 11)); - SIG_EXPR_LIST_DECL_SEMG(C23, PWM11, PWM11G0, PWM11, SIG_DESC_SET(SCU4B4, 11)); --PIN_DECL_2(C23, GPIOF3, SD1DAT1, PWM11); -+SIG_EXPR_LIST_DECL_SESG(C23, VPADE, VPA, SIG_DESC_CLEAR(SCU414, 11), -+ SIG_DESC_CLEAR(SCU4B4, 11)); -+PIN_DECL_3(C23, GPIOF3, SD1DAT1, PWM11, VPADE); - GROUP_DECL(PWM11G0, C23); - -+FUNC_GROUP_DECL(VPA, H24, J22, H22, H23, G22, F22, G23, G24, F23, F26, F25, -+ E26, F24, E23, E24, E25, D26, D24, C25, C26, C24, B26, B25, -+ B24, D22, E22, D23, C23); -+ - #define C22 44 - SIG_EXPR_LIST_DECL_SESG(C22, SD1DAT2, SD1, SIG_DESC_SET(SCU414, 12)); - SIG_EXPR_LIST_DECL_SEMG(C22, PWM12, PWM12G0, PWM12, SIG_DESC_SET(SCU4B4, 12)); -@@ -414,7 +476,7 @@ - #define E21 48 - SIG_EXPR_LIST_DECL_SESG(E21, TXD6, UART6, SIG_DESC_SET(SCU414, 16)); - SIG_EXPR_LIST_DECL_SESG(E21, SD2CLK, SD2, SIG_DESC_SET(SCU4B4, 16), -- SIG_DESC_SET(SCU450, 1)); -+ SIG_DESC_SET(SCU450, 1)); - SIG_EXPR_LIST_DECL_SEMG(E21, SALT9, SALT9G0, SALT9, SIG_DESC_SET(SCU694, 16)); - PIN_DECL_3(E21, GPIOG0, TXD6, SD2CLK, SALT9); - GROUP_DECL(SALT9G0, E21); -@@ -422,7 +484,7 @@ - #define B22 49 - SIG_EXPR_LIST_DECL_SESG(B22, RXD6, UART6, SIG_DESC_SET(SCU414, 17)); - SIG_EXPR_LIST_DECL_SESG(B22, SD2CMD, SD2, SIG_DESC_SET(SCU4B4, 17), -- SIG_DESC_SET(SCU450, 1)); -+ SIG_DESC_SET(SCU450, 1)); - SIG_EXPR_LIST_DECL_SEMG(B22, SALT10, SALT10G0, SALT10, - SIG_DESC_SET(SCU694, 17)); - PIN_DECL_3(B22, GPIOG1, RXD6, SD2CMD, SALT10); -@@ -433,7 +495,7 @@ - #define C21 50 - SIG_EXPR_LIST_DECL_SESG(C21, TXD7, UART7, SIG_DESC_SET(SCU414, 18)); - SIG_EXPR_LIST_DECL_SESG(C21, SD2DAT0, SD2, SIG_DESC_SET(SCU4B4, 18), -- SIG_DESC_SET(SCU450, 1)); -+ SIG_DESC_SET(SCU450, 1)); - SIG_EXPR_LIST_DECL_SEMG(C21, SALT11, SALT11G0, SALT11, - SIG_DESC_SET(SCU694, 18)); - PIN_DECL_3(C21, GPIOG2, TXD7, SD2DAT0, SALT11); -@@ -442,7 +504,7 @@ - #define A22 51 - SIG_EXPR_LIST_DECL_SESG(A22, RXD7, UART7, SIG_DESC_SET(SCU414, 19)); - SIG_EXPR_LIST_DECL_SESG(A22, SD2DAT1, SD2, SIG_DESC_SET(SCU4B4, 19), -- SIG_DESC_SET(SCU450, 1)); -+ SIG_DESC_SET(SCU450, 1)); - SIG_EXPR_LIST_DECL_SEMG(A22, SALT12, SALT12G0, SALT12, - SIG_DESC_SET(SCU694, 19)); - PIN_DECL_3(A22, GPIOG3, RXD7, SD2DAT1, SALT12); -@@ -453,7 +515,7 @@ - #define A21 52 - SIG_EXPR_LIST_DECL_SESG(A21, TXD8, UART8, SIG_DESC_SET(SCU414, 20)); - SIG_EXPR_LIST_DECL_SESG(A21, SD2DAT2, SD2, SIG_DESC_SET(SCU4B4, 20), -- SIG_DESC_SET(SCU450, 1)); -+ SIG_DESC_SET(SCU450, 1)); - SIG_EXPR_LIST_DECL_SEMG(A21, SALT13, SALT13G0, SALT13, - SIG_DESC_SET(SCU694, 20)); - PIN_DECL_3(A21, GPIOG4, TXD8, SD2DAT2, SALT13); -@@ -462,7 +524,7 @@ - #define E20 53 - SIG_EXPR_LIST_DECL_SESG(E20, RXD8, UART8, SIG_DESC_SET(SCU414, 21)); - SIG_EXPR_LIST_DECL_SESG(E20, SD2DAT3, SD2, SIG_DESC_SET(SCU4B4, 21), -- SIG_DESC_SET(SCU450, 1)); -+ SIG_DESC_SET(SCU450, 1)); - SIG_EXPR_LIST_DECL_SEMG(E20, SALT14, SALT14G0, SALT14, - SIG_DESC_SET(SCU694, 21)); - PIN_DECL_3(E20, GPIOG5, RXD8, SD2DAT3, SALT14); -@@ -473,7 +535,7 @@ - #define D21 54 - SIG_EXPR_LIST_DECL_SESG(D21, TXD9, UART9, SIG_DESC_SET(SCU414, 22)); - SIG_EXPR_LIST_DECL_SESG(D21, SD2CD, SD2, SIG_DESC_SET(SCU4B4, 22), -- SIG_DESC_SET(SCU450, 1)); -+ SIG_DESC_SET(SCU450, 1)); - SIG_EXPR_LIST_DECL_SEMG(D21, SALT15, SALT15G0, SALT15, - SIG_DESC_SET(SCU694, 22)); - PIN_DECL_3(D21, GPIOG6, TXD9, SD2CD, SALT15); -@@ -583,116 +645,150 @@ - FUNC_GROUP_DECL(SIOSCI, A15); - - #define B20 72 --SIG_EXPR_LIST_DECL_SEMG(B20, I3C3SCL, HVI3C3, I3C3, SIG_DESC_SET(SCU418, 8)); -+SIG_EXPR_LIST_DECL_SEMG(B20, I3C3SCL, HVI3C3, I3C3, SIG_DESC_SET(SCU418, 8), -+ SIG_DESC_CLEAR(SCU438, 20)); - SIG_EXPR_LIST_DECL_SESG(B20, SCL1, I2C1, SIG_DESC_SET(SCU4B8, 8)); --PIN_DECL_2(B20, GPIOJ0, I3C3SCL, SCL1); -+SIG_EXPR_LIST_DECL_SESG(B20, SSCL1, SI2C1, SIG_DESC_SET(SCU698, 8)); -+PIN_DECL_3(B20, GPIOJ0, I3C3SCL, SCL1, SSCL1); - - #define A20 73 --SIG_EXPR_LIST_DECL_SEMG(A20, I3C3SDA, HVI3C3, I3C3, SIG_DESC_SET(SCU418, 9)); -+SIG_EXPR_LIST_DECL_SEMG(A20, I3C3SDA, HVI3C3, I3C3, SIG_DESC_SET(SCU418, 9), -+ SIG_DESC_CLEAR(SCU438, 21)); - SIG_EXPR_LIST_DECL_SESG(A20, SDA1, I2C1, SIG_DESC_SET(SCU4B8, 9)); --PIN_DECL_2(A20, GPIOJ1, I3C3SDA, SDA1); -+SIG_EXPR_LIST_DECL_SESG(A20, SSDA1, SI2C1, SIG_DESC_SET(SCU698, 9)); -+PIN_DECL_3(A20, GPIOJ1, I3C3SDA, SDA1, SSDA1); - - GROUP_DECL(HVI3C3, B20, A20); - FUNC_GROUP_DECL(I2C1, B20, A20); -+FUNC_GROUP_DECL(SI2C1, B20, A20); - - #define E19 74 --SIG_EXPR_LIST_DECL_SEMG(E19, I3C4SCL, HVI3C4, I3C4, SIG_DESC_SET(SCU418, 10)); -+SIG_EXPR_LIST_DECL_SEMG(E19, I3C4SCL, HVI3C4, I3C4, SIG_DESC_SET(SCU418, 10), -+ SIG_DESC_CLEAR(SCU438, 22)); - SIG_EXPR_LIST_DECL_SESG(E19, SCL2, I2C2, SIG_DESC_SET(SCU4B8, 10)); --PIN_DECL_2(E19, GPIOJ2, I3C4SCL, SCL2); -+SIG_EXPR_LIST_DECL_SESG(E19, SSCL2, SI2C2, SIG_DESC_SET(SCU698, 10)); -+PIN_DECL_3(E19, GPIOJ2, I3C4SCL, SCL2, SSCL2); - - #define D20 75 --SIG_EXPR_LIST_DECL_SEMG(D20, I3C4SDA, HVI3C4, I3C4, SIG_DESC_SET(SCU418, 11)); -+SIG_EXPR_LIST_DECL_SEMG(D20, I3C4SDA, HVI3C4, I3C4, SIG_DESC_SET(SCU418, 11), -+ SIG_DESC_CLEAR(SCU438, 23)); - SIG_EXPR_LIST_DECL_SESG(D20, SDA2, I2C2, SIG_DESC_SET(SCU4B8, 11)); --PIN_DECL_2(D20, GPIOJ3, I3C4SDA, SDA2); -+SIG_EXPR_LIST_DECL_SESG(D20, SSDA2, SI2C2, SIG_DESC_SET(SCU698, 11)); -+PIN_DECL_3(D20, GPIOJ3, I3C4SDA, SDA2, SSDA2); - - GROUP_DECL(HVI3C4, E19, D20); - FUNC_GROUP_DECL(I2C2, E19, D20); -+FUNC_GROUP_DECL(SI2C2, E19, D20); - - #define C19 76 - SIG_EXPR_LIST_DECL_SESG(C19, I3C5SCL, I3C5, SIG_DESC_SET(SCU418, 12)); - SIG_EXPR_LIST_DECL_SESG(C19, SCL3, I2C3, SIG_DESC_SET(SCU4B8, 12)); --PIN_DECL_2(C19, GPIOJ4, I3C5SCL, SCL3); -+SIG_EXPR_LIST_DECL_SESG(C19, SSCL3, SI2C3, SIG_DESC_SET(SCU698, 12)); -+PIN_DECL_3(C19, GPIOJ4, I3C5SCL, SCL3, SSCL3); - - #define A19 77 - SIG_EXPR_LIST_DECL_SESG(A19, I3C5SDA, I3C5, SIG_DESC_SET(SCU418, 13)); - SIG_EXPR_LIST_DECL_SESG(A19, SDA3, I2C3, SIG_DESC_SET(SCU4B8, 13)); --PIN_DECL_2(A19, GPIOJ5, I3C5SDA, SDA3); -+SIG_EXPR_LIST_DECL_SESG(A19, SSDA3, SI2C3, SIG_DESC_SET(SCU698, 13)); -+PIN_DECL_3(A19, GPIOJ5, I3C5SDA, SDA3, SSDA3); - - FUNC_GROUP_DECL(I3C5, C19, A19); - FUNC_GROUP_DECL(I2C3, C19, A19); -+FUNC_GROUP_DECL(SI2C3, C19, A19); - - #define C20 78 - SIG_EXPR_LIST_DECL_SESG(C20, I3C6SCL, I3C6, SIG_DESC_SET(SCU418, 14)); - SIG_EXPR_LIST_DECL_SESG(C20, SCL4, I2C4, SIG_DESC_SET(SCU4B8, 14)); --PIN_DECL_2(C20, GPIOJ6, I3C6SCL, SCL4); -+SIG_EXPR_LIST_DECL_SESG(C20, SSCL4, SI2C4, SIG_DESC_SET(SCU698, 14)); -+PIN_DECL_3(C20, GPIOJ6, I3C6SCL, SCL4, SSCL4); - - #define D19 79 - SIG_EXPR_LIST_DECL_SESG(D19, I3C6SDA, I3C6, SIG_DESC_SET(SCU418, 15)); - SIG_EXPR_LIST_DECL_SESG(D19, SDA4, I2C4, SIG_DESC_SET(SCU4B8, 15)); --PIN_DECL_2(D19, GPIOJ7, I3C6SDA, SDA4); -+SIG_EXPR_LIST_DECL_SESG(D19, SSDA4, SI2C4, SIG_DESC_SET(SCU698, 15)); -+PIN_DECL_3(D19, GPIOJ7, I3C6SDA, SDA4, SSDA4); - - FUNC_GROUP_DECL(I3C6, C20, D19); - FUNC_GROUP_DECL(I2C4, C20, D19); -+FUNC_GROUP_DECL(SI2C4, C20, D19); - - #define A11 80 - SIG_EXPR_LIST_DECL_SESG(A11, SCL5, I2C5, SIG_DESC_SET(SCU418, 16)); --PIN_DECL_1(A11, GPIOK0, SCL5); -+SIG_EXPR_LIST_DECL_SESG(A11, SSCL5, SI2C5, SIG_DESC_SET(SCU4B8, 16)); -+PIN_DECL_2(A11, GPIOK0, SCL5, SSCL5); - - #define C11 81 - SIG_EXPR_LIST_DECL_SESG(C11, SDA5, I2C5, SIG_DESC_SET(SCU418, 17)); --PIN_DECL_1(C11, GPIOK1, SDA5); -+SIG_EXPR_LIST_DECL_SESG(C11, SSDA5, SI2C5, SIG_DESC_SET(SCU4B8, 17)); -+PIN_DECL_2(C11, GPIOK1, SDA5, SSDA5); - - FUNC_GROUP_DECL(I2C5, A11, C11); -+FUNC_GROUP_DECL(SI2C5, A11, C11); - - #define D12 82 - SIG_EXPR_LIST_DECL_SESG(D12, SCL6, I2C6, SIG_DESC_SET(SCU418, 18)); --PIN_DECL_1(D12, GPIOK2, SCL6); -+SIG_EXPR_LIST_DECL_SESG(D12, SSCL6, SI2C6, SIG_DESC_SET(SCU4B8, 18)); -+PIN_DECL_2(D12, GPIOK2, SCL6, SSCL6); - - #define E13 83 - SIG_EXPR_LIST_DECL_SESG(E13, SDA6, I2C6, SIG_DESC_SET(SCU418, 19)); --PIN_DECL_1(E13, GPIOK3, SDA6); -+SIG_EXPR_LIST_DECL_SESG(E13, SSDA6, SI2C6, SIG_DESC_SET(SCU4B8, 19)); -+PIN_DECL_2(E13, GPIOK3, SDA6, SSDA6); - - FUNC_GROUP_DECL(I2C6, D12, E13); -+FUNC_GROUP_DECL(SI2C6, D12, E13); - - #define D11 84 - SIG_EXPR_LIST_DECL_SESG(D11, SCL7, I2C7, SIG_DESC_SET(SCU418, 20)); --PIN_DECL_1(D11, GPIOK4, SCL7); -+SIG_EXPR_LIST_DECL_SESG(D11, SSCL7, SI2C7, SIG_DESC_SET(SCU4B8, 20)); -+PIN_DECL_2(D11, GPIOK4, SCL7, SSCL7); - - #define E11 85 - SIG_EXPR_LIST_DECL_SESG(E11, SDA7, I2C7, SIG_DESC_SET(SCU418, 21)); --PIN_DECL_1(E11, GPIOK5, SDA7); -+SIG_EXPR_LIST_DECL_SESG(E11, SSDA7, SI2C7, SIG_DESC_SET(SCU4B8, 21)); -+PIN_DECL_2(E11, GPIOK5, SDA7, SSDA7); - - FUNC_GROUP_DECL(I2C7, D11, E11); -+FUNC_GROUP_DECL(SI2C7, D11, E11); - - #define F13 86 - SIG_EXPR_LIST_DECL_SESG(F13, SCL8, I2C8, SIG_DESC_SET(SCU418, 22)); --PIN_DECL_1(F13, GPIOK6, SCL8); -+SIG_EXPR_LIST_DECL_SESG(F13, SSCL8, SI2C8, SIG_DESC_SET(SCU4B8, 22)); -+PIN_DECL_2(F13, GPIOK6, SCL8, SSCL8); - - #define E12 87 - SIG_EXPR_LIST_DECL_SESG(E12, SDA8, I2C8, SIG_DESC_SET(SCU418, 23)); --PIN_DECL_1(E12, GPIOK7, SDA8); -+SIG_EXPR_LIST_DECL_SESG(E12, SSDA8, SI2C8, SIG_DESC_SET(SCU4B8, 23)); -+PIN_DECL_2(E12, GPIOK7, SDA8, SSDA8); - - FUNC_GROUP_DECL(I2C8, F13, E12); -+FUNC_GROUP_DECL(SI2C8, F13, E12); - - #define D15 88 - SIG_EXPR_LIST_DECL_SESG(D15, SCL9, I2C9, SIG_DESC_SET(SCU418, 24)); --PIN_DECL_1(D15, GPIOL0, SCL9); -+SIG_EXPR_LIST_DECL_SESG(D15, SSCL9, SI2C9, SIG_DESC_SET(SCU4B8, 24)); -+PIN_DECL_2(D15, GPIOL0, SCL9, SSCL9); - - #define A14 89 - SIG_EXPR_LIST_DECL_SESG(A14, SDA9, I2C9, SIG_DESC_SET(SCU418, 25)); --PIN_DECL_1(A14, GPIOL1, SDA9); -+SIG_EXPR_LIST_DECL_SESG(A14, SSDA9, SI2C9, SIG_DESC_SET(SCU4B8, 25)); -+PIN_DECL_2(A14, GPIOL1, SDA9, SSDA9); - - FUNC_GROUP_DECL(I2C9, D15, A14); -+FUNC_GROUP_DECL(SI2C9, D15, A14); - - #define E15 90 - SIG_EXPR_LIST_DECL_SESG(E15, SCL10, I2C10, SIG_DESC_SET(SCU418, 26)); --PIN_DECL_1(E15, GPIOL2, SCL10); -+SIG_EXPR_LIST_DECL_SESG(E15, SSCL10, SI2C10, SIG_DESC_SET(SCU4B8, 26)); -+PIN_DECL_2(E15, GPIOL2, SCL10, SSCL10); - - #define A13 91 - SIG_EXPR_LIST_DECL_SESG(A13, SDA10, I2C10, SIG_DESC_SET(SCU418, 27)); --PIN_DECL_1(A13, GPIOL3, SDA10); -+SIG_EXPR_LIST_DECL_SESG(A13, SSDA10, SI2C10, SIG_DESC_SET(SCU4B8, 27)); -+PIN_DECL_2(A13, GPIOL3, SDA10, SSDA10); - - FUNC_GROUP_DECL(I2C10, E15, A13); -+FUNC_GROUP_DECL(SI2C10, E15, A13); - - #define C15 92 - SSSF_PIN_DECL(C15, GPIOL4, TXD3, SIG_DESC_SET(SCU418, 28)); -@@ -987,9 +1083,8 @@ - - #define AB16 160 - SIG_EXPR_LIST_DECL_SEMG(AB16, SALT9, SALT9G1, SALT9, SIG_DESC_SET(SCU434, 0), -- SIG_DESC_CLEAR(SCU694, 16)); --SIG_EXPR_LIST_DECL_SESG(AB16, GPIU0, GPIU0, SIG_DESC_SET(SCU434, 0), -- SIG_DESC_SET(SCU694, 16)); -+ SIG_DESC_CLEAR(SCU694, 16), SIG_DESC_SET(SCU4D4, 0)); -+SIG_EXPR_LIST_DECL_SESG(AB16, GPIU0, GPIU0, SIG_DESC_SET(SCU434, 0)); - SIG_EXPR_LIST_DECL_SESG(AB16, ADC8, ADC8); - PIN_DECL_(AB16, SIG_EXPR_LIST_PTR(AB16, SALT9), SIG_EXPR_LIST_PTR(AB16, GPIU0), - SIG_EXPR_LIST_PTR(AB16, ADC8)); -@@ -1000,9 +1095,8 @@ - - #define AA17 161 - SIG_EXPR_LIST_DECL_SEMG(AA17, SALT10, SALT10G1, SALT10, SIG_DESC_SET(SCU434, 1), -- SIG_DESC_CLEAR(SCU694, 17)); --SIG_EXPR_LIST_DECL_SESG(AA17, GPIU1, GPIU1, SIG_DESC_SET(SCU434, 1), -- SIG_DESC_SET(SCU694, 17)); -+ SIG_DESC_CLEAR(SCU694, 17), SIG_DESC_SET(SCU4D4, 1)); -+SIG_EXPR_LIST_DECL_SESG(AA17, GPIU1, GPIU1, SIG_DESC_SET(SCU434, 1)); - SIG_EXPR_LIST_DECL_SESG(AA17, ADC9, ADC9); - PIN_DECL_(AA17, SIG_EXPR_LIST_PTR(AA17, SALT10), SIG_EXPR_LIST_PTR(AA17, GPIU1), - SIG_EXPR_LIST_PTR(AA17, ADC9)); -@@ -1013,9 +1107,8 @@ - - #define AB17 162 - SIG_EXPR_LIST_DECL_SEMG(AB17, SALT11, SALT11G1, SALT11, SIG_DESC_SET(SCU434, 2), -- SIG_DESC_CLEAR(SCU694, 18)); --SIG_EXPR_LIST_DECL_SESG(AB17, GPIU2, GPIU2, SIG_DESC_SET(SCU434, 2), -- SIG_DESC_SET(SCU694, 18)); -+ SIG_DESC_CLEAR(SCU694, 18), SIG_DESC_SET(SCU4D4, 2)); -+SIG_EXPR_LIST_DECL_SESG(AB17, GPIU2, GPIU2, SIG_DESC_SET(SCU434, 2)); - SIG_EXPR_LIST_DECL_SESG(AB17, ADC10, ADC10); - PIN_DECL_(AB17, SIG_EXPR_LIST_PTR(AB17, SALT11), SIG_EXPR_LIST_PTR(AB17, GPIU2), - SIG_EXPR_LIST_PTR(AB17, ADC10)); -@@ -1026,9 +1119,8 @@ - - #define AE16 163 - SIG_EXPR_LIST_DECL_SEMG(AE16, SALT12, SALT12G1, SALT12, SIG_DESC_SET(SCU434, 3), -- SIG_DESC_CLEAR(SCU694, 19)); --SIG_EXPR_LIST_DECL_SESG(AE16, GPIU3, GPIU3, SIG_DESC_SET(SCU434, 3), -- SIG_DESC_SET(SCU694, 19)); -+ SIG_DESC_CLEAR(SCU694, 19), SIG_DESC_SET(SCU4D4, 3)); -+SIG_EXPR_LIST_DECL_SESG(AE16, GPIU3, GPIU3, SIG_DESC_SET(SCU434, 3)); - SIG_EXPR_LIST_DECL_SESG(AE16, ADC11, ADC11); - PIN_DECL_(AE16, SIG_EXPR_LIST_PTR(AE16, SALT12), SIG_EXPR_LIST_PTR(AE16, GPIU3), - SIG_EXPR_LIST_PTR(AE16, ADC11)); -@@ -1039,9 +1131,8 @@ - - #define AC16 164 - SIG_EXPR_LIST_DECL_SEMG(AC16, SALT13, SALT13G1, SALT13, SIG_DESC_SET(SCU434, 4), -- SIG_DESC_CLEAR(SCU694, 20)); --SIG_EXPR_LIST_DECL_SESG(AC16, GPIU4, GPIU4, SIG_DESC_SET(SCU434, 4), -- SIG_DESC_SET(SCU694, 20)); -+ SIG_DESC_CLEAR(SCU694, 20), SIG_DESC_SET(SCU4D4, 4)); -+SIG_EXPR_LIST_DECL_SESG(AC16, GPIU4, GPIU4, SIG_DESC_SET(SCU434, 4)); - SIG_EXPR_LIST_DECL_SESG(AC16, ADC12, ADC12); - PIN_DECL_(AC16, SIG_EXPR_LIST_PTR(AC16, SALT13), SIG_EXPR_LIST_PTR(AC16, GPIU4), - SIG_EXPR_LIST_PTR(AC16, ADC12)); -@@ -1052,9 +1143,8 @@ - - #define AA16 165 - SIG_EXPR_LIST_DECL_SEMG(AA16, SALT14, SALT14G1, SALT14, SIG_DESC_SET(SCU434, 5), -- SIG_DESC_CLEAR(SCU694, 21)); --SIG_EXPR_LIST_DECL_SESG(AA16, GPIU5, GPIU5, SIG_DESC_SET(SCU434, 5), -- SIG_DESC_SET(SCU694, 21)); -+ SIG_DESC_CLEAR(SCU694, 21), SIG_DESC_SET(SCU4D4, 5)); -+SIG_EXPR_LIST_DECL_SESG(AA16, GPIU5, GPIU5, SIG_DESC_SET(SCU434, 5)); - SIG_EXPR_LIST_DECL_SESG(AA16, ADC13, ADC13); - PIN_DECL_(AA16, SIG_EXPR_LIST_PTR(AA16, SALT14), SIG_EXPR_LIST_PTR(AA16, GPIU5), - SIG_EXPR_LIST_PTR(AA16, ADC13)); -@@ -1065,9 +1155,8 @@ - - #define AD16 166 - SIG_EXPR_LIST_DECL_SEMG(AD16, SALT15, SALT15G1, SALT15, SIG_DESC_SET(SCU434, 6), -- SIG_DESC_CLEAR(SCU694, 22)); --SIG_EXPR_LIST_DECL_SESG(AD16, GPIU6, GPIU6, SIG_DESC_SET(SCU434, 6), -- SIG_DESC_SET(SCU694, 22)); -+ SIG_DESC_CLEAR(SCU694, 22), SIG_DESC_SET(SCU4D4, 6)); -+SIG_EXPR_LIST_DECL_SESG(AD16, GPIU6, GPIU6, SIG_DESC_SET(SCU434, 6)); - SIG_EXPR_LIST_DECL_SESG(AD16, ADC14, ADC14); - PIN_DECL_(AD16, SIG_EXPR_LIST_PTR(AD16, SALT15), SIG_EXPR_LIST_PTR(AD16, GPIU6), - SIG_EXPR_LIST_PTR(AD16, ADC14)); -@@ -1078,9 +1167,8 @@ - - #define AC17 167 - SIG_EXPR_LIST_DECL_SEMG(AC17, SALT16, SALT16G1, SALT16, SIG_DESC_SET(SCU434, 7), -- SIG_DESC_CLEAR(SCU694, 23)); --SIG_EXPR_LIST_DECL_SESG(AC17, GPIU7, GPIU7, SIG_DESC_SET(SCU434, 7), -- SIG_DESC_SET(SCU694, 23)); -+ SIG_DESC_CLEAR(SCU694, 23), SIG_DESC_SET(SCU4D4, 7)); -+SIG_EXPR_LIST_DECL_SESG(AC17, GPIU7, GPIU7, SIG_DESC_SET(SCU434, 7)); - SIG_EXPR_LIST_DECL_SESG(AC17, ADC15, ADC15); - PIN_DECL_(AC17, SIG_EXPR_LIST_PTR(AC17, SALT16), SIG_EXPR_LIST_PTR(AC17, GPIU7), - SIG_EXPR_LIST_PTR(AC17, ADC15)); -@@ -1205,7 +1293,7 @@ - SIG_DESC_SET(SCU4D4, 31)); - PIN_DECL_2(AB10, GPIOX7, SPI2DQ3, RXD12); - --GROUP_DECL(QSPI2, AE8, AF8, AB9, AD9, AF9, AB10); -+GROUP_DECL(QSPI2, AF9, AB10); - FUNC_DECL_2(SPI2, SPI2, QSPI2); - - GROUP_DECL(UART12G1, AF9, AB10); -@@ -1240,15 +1328,21 @@ - FUNC_GROUP_DECL(WDTRST4, AA12); - - #define AE12 196 -+SIG_EXPR_LIST_DECL_SEMG(AE12, FWSPIDQ2, FWQSPID, FWSPID, -+ SIG_DESC_SET(SCU438, 4)); - SIG_EXPR_LIST_DECL_SESG(AE12, FWSPIQ2, FWQSPI, SIG_DESC_SET(SCU438, 4)); - SIG_EXPR_LIST_DECL_SESG(AE12, GPIOY4, GPIOY4); --PIN_DECL_(AE12, SIG_EXPR_LIST_PTR(AE12, FWSPIQ2), -+PIN_DECL_(AE12, SIG_EXPR_LIST_PTR(AE12, FWSPIDQ2), -+ SIG_EXPR_LIST_PTR(AE12, FWSPIQ2), - SIG_EXPR_LIST_PTR(AE12, GPIOY4)); - - #define AF12 197 -+SIG_EXPR_LIST_DECL_SEMG(AF12, FWSPIDQ3, FWQSPID, FWSPID, -+ SIG_DESC_SET(SCU438, 5)); - SIG_EXPR_LIST_DECL_SESG(AF12, FWSPIQ3, FWQSPI, SIG_DESC_SET(SCU438, 5)); - SIG_EXPR_LIST_DECL_SESG(AF12, GPIOY5, GPIOY5); --PIN_DECL_(AF12, SIG_EXPR_LIST_PTR(AF12, FWSPIQ3), -+PIN_DECL_(AF12, SIG_EXPR_LIST_PTR(AF12, FWSPIDQ3), -+ SIG_EXPR_LIST_PTR(AF12, FWSPIQ3), - SIG_EXPR_LIST_PTR(AF12, GPIOY5)); - FUNC_GROUP_DECL(FWQSPI, AE12, AF12); - -@@ -1293,7 +1387,7 @@ - SIG_DESC_CLEAR(SCU4B8, 3), SIG_DESC_SET(SCU4D8, 15)); - PIN_DECL_2(AF10, GPIOZ7, SPI1DQ3, RXD13); - --GROUP_DECL(QSPI1, AB11, AC11, AA11, AD11, AF10); -+GROUP_DECL(QSPI1, AD11, AF10); - FUNC_DECL_2(SPI1, SPI1, QSPI1); - - GROUP_DECL(UART13G1, AD11, AF10); -@@ -1301,80 +1395,80 @@ - - #define C6 208 - SIG_EXPR_LIST_DECL_SESG(C6, RGMII1TXCK, RGMII1, SIG_DESC_SET(SCU400, 0), -- SIG_DESC_SET(SCU500, 6)); -+ SIG_DESC_SET(SCU500, 6)); - SIG_EXPR_LIST_DECL_SESG(C6, RMII1RCLKO, RMII1, SIG_DESC_SET(SCU400, 0), -- SIG_DESC_CLEAR(SCU500, 6)); -+ SIG_DESC_CLEAR(SCU500, 6)); - PIN_DECL_2(C6, GPIO18A0, RGMII1TXCK, RMII1RCLKO); - - #define D6 209 - SIG_EXPR_LIST_DECL_SESG(D6, RGMII1TXCTL, RGMII1, SIG_DESC_SET(SCU400, 1), -- SIG_DESC_SET(SCU500, 6)); -+ SIG_DESC_SET(SCU500, 6)); - SIG_EXPR_LIST_DECL_SESG(D6, RMII1TXEN, RMII1, SIG_DESC_SET(SCU400, 1), -- SIG_DESC_CLEAR(SCU500, 6)); -+ SIG_DESC_CLEAR(SCU500, 6)); - PIN_DECL_2(D6, GPIO18A1, RGMII1TXCTL, RMII1TXEN); - - #define D5 210 - SIG_EXPR_LIST_DECL_SESG(D5, RGMII1TXD0, RGMII1, SIG_DESC_SET(SCU400, 2), -- SIG_DESC_SET(SCU500, 6)); -+ SIG_DESC_SET(SCU500, 6)); - SIG_EXPR_LIST_DECL_SESG(D5, RMII1TXD0, RMII1, SIG_DESC_SET(SCU400, 2), -- SIG_DESC_CLEAR(SCU500, 6)); -+ SIG_DESC_CLEAR(SCU500, 6)); - PIN_DECL_2(D5, GPIO18A2, RGMII1TXD0, RMII1TXD0); - - #define A3 211 - SIG_EXPR_LIST_DECL_SESG(A3, RGMII1TXD1, RGMII1, SIG_DESC_SET(SCU400, 3), -- SIG_DESC_SET(SCU500, 6)); -+ SIG_DESC_SET(SCU500, 6)); - SIG_EXPR_LIST_DECL_SESG(A3, RMII1TXD1, RMII1, SIG_DESC_SET(SCU400, 3), -- SIG_DESC_CLEAR(SCU500, 6)); -+ SIG_DESC_CLEAR(SCU500, 6)); - PIN_DECL_2(A3, GPIO18A3, RGMII1TXD1, RMII1TXD1); - - #define C5 212 - SIG_EXPR_LIST_DECL_SESG(C5, RGMII1TXD2, RGMII1, SIG_DESC_SET(SCU400, 4), -- SIG_DESC_SET(SCU500, 6)); -+ SIG_DESC_SET(SCU500, 6)); - PIN_DECL_1(C5, GPIO18A4, RGMII1TXD2); - - #define E6 213 - SIG_EXPR_LIST_DECL_SESG(E6, RGMII1TXD3, RGMII1, SIG_DESC_SET(SCU400, 5), -- SIG_DESC_SET(SCU500, 6)); -+ SIG_DESC_SET(SCU500, 6)); - PIN_DECL_1(E6, GPIO18A5, RGMII1TXD3); - - #define B3 214 - SIG_EXPR_LIST_DECL_SESG(B3, RGMII1RXCK, RGMII1, SIG_DESC_SET(SCU400, 6), -- SIG_DESC_SET(SCU500, 6)); -+ SIG_DESC_SET(SCU500, 6)); - SIG_EXPR_LIST_DECL_SESG(B3, RMII1RCLKI, RMII1, SIG_DESC_SET(SCU400, 6), -- SIG_DESC_CLEAR(SCU500, 6)); -+ SIG_DESC_CLEAR(SCU500, 6)); - PIN_DECL_2(B3, GPIO18A6, RGMII1RXCK, RMII1RCLKI); - - #define A2 215 - SIG_EXPR_LIST_DECL_SESG(A2, RGMII1RXCTL, RGMII1, SIG_DESC_SET(SCU400, 7), -- SIG_DESC_SET(SCU500, 6)); -+ SIG_DESC_SET(SCU500, 6)); - PIN_DECL_1(A2, GPIO18A7, RGMII1RXCTL); - - #define B2 216 - SIG_EXPR_LIST_DECL_SESG(B2, RGMII1RXD0, RGMII1, SIG_DESC_SET(SCU400, 8), -- SIG_DESC_SET(SCU500, 6)); -+ SIG_DESC_SET(SCU500, 6)); - SIG_EXPR_LIST_DECL_SESG(B2, RMII1RXD0, RMII1, SIG_DESC_SET(SCU400, 8), -- SIG_DESC_CLEAR(SCU500, 6)); -+ SIG_DESC_CLEAR(SCU500, 6)); - PIN_DECL_2(B2, GPIO18B0, RGMII1RXD0, RMII1RXD0); - - #define B1 217 - SIG_EXPR_LIST_DECL_SESG(B1, RGMII1RXD1, RGMII1, SIG_DESC_SET(SCU400, 9), -- SIG_DESC_SET(SCU500, 6)); -+ SIG_DESC_SET(SCU500, 6)); - SIG_EXPR_LIST_DECL_SESG(B1, RMII1RXD1, RMII1, SIG_DESC_SET(SCU400, 9), -- SIG_DESC_CLEAR(SCU500, 6)); -+ SIG_DESC_CLEAR(SCU500, 6)); - PIN_DECL_2(B1, GPIO18B1, RGMII1RXD1, RMII1RXD1); - - #define C4 218 - SIG_EXPR_LIST_DECL_SESG(C4, RGMII1RXD2, RGMII1, SIG_DESC_SET(SCU400, 10), -- SIG_DESC_SET(SCU500, 6)); -+ SIG_DESC_SET(SCU500, 6)); - SIG_EXPR_LIST_DECL_SESG(C4, RMII1CRSDV, RMII1, SIG_DESC_SET(SCU400, 10), -- SIG_DESC_CLEAR(SCU500, 6)); -+ SIG_DESC_CLEAR(SCU500, 6)); - PIN_DECL_2(C4, GPIO18B2, RGMII1RXD2, RMII1CRSDV); - - #define E5 219 - SIG_EXPR_LIST_DECL_SESG(E5, RGMII1RXD3, RGMII1, SIG_DESC_SET(SCU400, 11), -- SIG_DESC_SET(SCU500, 6)); -+ SIG_DESC_SET(SCU500, 6)); - SIG_EXPR_LIST_DECL_SESG(E5, RMII1RXER, RMII1, SIG_DESC_SET(SCU400, 11), -- SIG_DESC_CLEAR(SCU500, 6)); -+ SIG_DESC_CLEAR(SCU500, 6)); - PIN_DECL_2(E5, GPIO18B3, RGMII1RXD3, RMII1RXER); - - FUNC_GROUP_DECL(RGMII1, C6, D6, D5, A3, C5, E6, B3, A2, B2, B1, C4, E5); -@@ -1382,80 +1476,80 @@ - - #define D4 220 - SIG_EXPR_LIST_DECL_SESG(D4, RGMII2TXCK, RGMII2, SIG_DESC_SET(SCU400, 12), -- SIG_DESC_SET(SCU500, 7)); -+ SIG_DESC_SET(SCU500, 7)); - SIG_EXPR_LIST_DECL_SESG(D4, RMII2RCLKO, RMII2, SIG_DESC_SET(SCU400, 12), -- SIG_DESC_CLEAR(SCU500, 7)); -+ SIG_DESC_CLEAR(SCU500, 7)); - PIN_DECL_2(D4, GPIO18B4, RGMII2TXCK, RMII2RCLKO); - - #define C2 221 - SIG_EXPR_LIST_DECL_SESG(C2, RGMII2TXCTL, RGMII2, SIG_DESC_SET(SCU400, 13), -- SIG_DESC_SET(SCU500, 7)); -+ SIG_DESC_SET(SCU500, 7)); - SIG_EXPR_LIST_DECL_SESG(C2, RMII2TXEN, RMII2, SIG_DESC_SET(SCU400, 13), -- SIG_DESC_CLEAR(SCU500, 7)); -+ SIG_DESC_CLEAR(SCU500, 7)); - PIN_DECL_2(C2, GPIO18B5, RGMII2TXCTL, RMII2TXEN); - - #define C1 222 - SIG_EXPR_LIST_DECL_SESG(C1, RGMII2TXD0, RGMII2, SIG_DESC_SET(SCU400, 14), -- SIG_DESC_SET(SCU500, 7)); -+ SIG_DESC_SET(SCU500, 7)); - SIG_EXPR_LIST_DECL_SESG(C1, RMII2TXD0, RMII2, SIG_DESC_SET(SCU400, 14), -- SIG_DESC_CLEAR(SCU500, 7)); -+ SIG_DESC_CLEAR(SCU500, 7)); - PIN_DECL_2(C1, GPIO18B6, RGMII2TXD0, RMII2TXD0); - - #define D3 223 - SIG_EXPR_LIST_DECL_SESG(D3, RGMII2TXD1, RGMII2, SIG_DESC_SET(SCU400, 15), -- SIG_DESC_SET(SCU500, 7)); -+ SIG_DESC_SET(SCU500, 7)); - SIG_EXPR_LIST_DECL_SESG(D3, RMII2TXD1, RMII2, SIG_DESC_SET(SCU400, 15), -- SIG_DESC_CLEAR(SCU500, 7)); -+ SIG_DESC_CLEAR(SCU500, 7)); - PIN_DECL_2(D3, GPIO18B7, RGMII2TXD1, RMII2TXD1); - - #define E4 224 - SIG_EXPR_LIST_DECL_SESG(E4, RGMII2TXD2, RGMII2, SIG_DESC_SET(SCU400, 16), -- SIG_DESC_SET(SCU500, 7)); -+ SIG_DESC_SET(SCU500, 7)); - PIN_DECL_1(E4, GPIO18C0, RGMII2TXD2); - - #define F5 225 - SIG_EXPR_LIST_DECL_SESG(F5, RGMII2TXD3, RGMII2, SIG_DESC_SET(SCU400, 17), -- SIG_DESC_SET(SCU500, 7)); -+ SIG_DESC_SET(SCU500, 7)); - PIN_DECL_1(F5, GPIO18C1, RGMII2TXD3); - - #define D2 226 - SIG_EXPR_LIST_DECL_SESG(D2, RGMII2RXCK, RGMII2, SIG_DESC_SET(SCU400, 18), -- SIG_DESC_SET(SCU500, 7)); -+ SIG_DESC_SET(SCU500, 7)); - SIG_EXPR_LIST_DECL_SESG(D2, RMII2RCLKI, RMII2, SIG_DESC_SET(SCU400, 18), -- SIG_DESC_CLEAR(SCU500, 7)); -+ SIG_DESC_CLEAR(SCU500, 7)); - PIN_DECL_2(D2, GPIO18C2, RGMII2RXCK, RMII2RCLKI); - - #define E3 227 - SIG_EXPR_LIST_DECL_SESG(E3, RGMII2RXCTL, RGMII2, SIG_DESC_SET(SCU400, 19), -- SIG_DESC_SET(SCU500, 7)); -+ SIG_DESC_SET(SCU500, 7)); - PIN_DECL_1(E3, GPIO18C3, RGMII2RXCTL); - - #define D1 228 - SIG_EXPR_LIST_DECL_SESG(D1, RGMII2RXD0, RGMII2, SIG_DESC_SET(SCU400, 20), -- SIG_DESC_SET(SCU500, 7)); -+ SIG_DESC_SET(SCU500, 7)); - SIG_EXPR_LIST_DECL_SESG(D1, RMII2RXD0, RMII2, SIG_DESC_SET(SCU400, 20), -- SIG_DESC_CLEAR(SCU500, 7)); -+ SIG_DESC_CLEAR(SCU500, 7)); - PIN_DECL_2(D1, GPIO18C4, RGMII2RXD0, RMII2RXD0); - - #define F4 229 - SIG_EXPR_LIST_DECL_SESG(F4, RGMII2RXD1, RGMII2, SIG_DESC_SET(SCU400, 21), -- SIG_DESC_SET(SCU500, 7)); -+ SIG_DESC_SET(SCU500, 7)); - SIG_EXPR_LIST_DECL_SESG(F4, RMII2RXD1, RMII2, SIG_DESC_SET(SCU400, 21), -- SIG_DESC_CLEAR(SCU500, 7)); -+ SIG_DESC_CLEAR(SCU500, 7)); - PIN_DECL_2(F4, GPIO18C5, RGMII2RXD1, RMII2RXD1); - - #define E2 230 - SIG_EXPR_LIST_DECL_SESG(E2, RGMII2RXD2, RGMII2, SIG_DESC_SET(SCU400, 22), -- SIG_DESC_SET(SCU500, 7)); -+ SIG_DESC_SET(SCU500, 7)); - SIG_EXPR_LIST_DECL_SESG(E2, RMII2CRSDV, RMII2, SIG_DESC_SET(SCU400, 22), -- SIG_DESC_CLEAR(SCU500, 7)); -+ SIG_DESC_CLEAR(SCU500, 7)); - PIN_DECL_2(E2, GPIO18C6, RGMII2RXD2, RMII2CRSDV); - - #define E1 231 - SIG_EXPR_LIST_DECL_SESG(E1, RGMII2RXD3, RGMII2, SIG_DESC_SET(SCU400, 23), -- SIG_DESC_SET(SCU500, 7)); -+ SIG_DESC_SET(SCU500, 7)); - SIG_EXPR_LIST_DECL_SESG(E1, RMII2RXER, RMII2, SIG_DESC_SET(SCU400, 23), -- SIG_DESC_CLEAR(SCU500, 7)); -+ SIG_DESC_CLEAR(SCU500, 7)); - PIN_DECL_2(E1, GPIO18C7, RGMII2RXD3, RMII2RXER); - - FUNC_GROUP_DECL(RGMII2, D4, C2, C1, D3, E4, F5, D2, E3, D1, F4, E2, E1); -@@ -1523,8 +1617,9 @@ - PIN_DECL_3(Y4, GPIO18E3, FWSPIDMISO, VBMISO, EMMCDAT7); - - GROUP_DECL(FWSPID, Y1, Y2, Y3, Y4); -+GROUP_DECL(FWQSPID, Y1, Y2, Y3, Y4, AE12, AF12); - GROUP_DECL(EMMCG8, AB4, AA4, AC4, AA5, Y5, AB5, AB6, AC5, Y1, Y2, Y3, Y4); --FUNC_DECL_1(FWSPID, FWSPID); -+FUNC_DECL_2(FWSPID, FWSPID, FWQSPID); - FUNC_GROUP_DECL(VB, Y1, Y2, Y3, Y4); - FUNC_DECL_3(EMMC, EMMCG1, EMMCG4, EMMCG8); - /* -@@ -1532,13 +1627,15 @@ - * following 4 pins - */ - #define AF25 244 --SIG_EXPR_LIST_DECL_SEMG(AF25, I3C3SCL, I3C3, I3C3, SIG_DESC_SET(SCU438, 20)); -+SIG_EXPR_LIST_DECL_SEMG(AF25, I3C3SCL, I3C3, I3C3, SIG_DESC_SET(SCU438, 20), -+ SIG_DESC_CLEAR(SCU418, 8)); - SIG_EXPR_LIST_DECL_SESG(AF25, FSI1CLK, FSI1, SIG_DESC_SET(SCU4D8, 20)); - PIN_DECL_(AF25, SIG_EXPR_LIST_PTR(AF25, I3C3SCL), - SIG_EXPR_LIST_PTR(AF25, FSI1CLK)); - - #define AE26 245 --SIG_EXPR_LIST_DECL_SEMG(AE26, I3C3SDA, I3C3, I3C3, SIG_DESC_SET(SCU438, 21)); -+SIG_EXPR_LIST_DECL_SEMG(AE26, I3C3SDA, I3C3, I3C3, SIG_DESC_SET(SCU438, 21), -+ SIG_DESC_CLEAR(SCU418, 9)); - SIG_EXPR_LIST_DECL_SESG(AE26, FSI1DATA, FSI1, SIG_DESC_SET(SCU4D8, 21)); - PIN_DECL_(AE26, SIG_EXPR_LIST_PTR(AE26, I3C3SDA), - SIG_EXPR_LIST_PTR(AE26, FSI1DATA)); -@@ -1548,13 +1645,15 @@ - FUNC_GROUP_DECL(FSI1, AF25, AE26); - - #define AE25 246 --SIG_EXPR_LIST_DECL_SEMG(AE25, I3C4SCL, I3C4, I3C4, SIG_DESC_SET(SCU438, 22)); -+SIG_EXPR_LIST_DECL_SEMG(AE25, I3C4SCL, I3C4, I3C4, SIG_DESC_SET(SCU438, 22), -+ SIG_DESC_CLEAR(SCU418, 10)); - SIG_EXPR_LIST_DECL_SESG(AE25, FSI2CLK, FSI2, SIG_DESC_SET(SCU4D8, 22)); - PIN_DECL_(AE25, SIG_EXPR_LIST_PTR(AE25, I3C4SCL), - SIG_EXPR_LIST_PTR(AE25, FSI2CLK)); - - #define AF24 247 --SIG_EXPR_LIST_DECL_SEMG(AF24, I3C4SDA, I3C4, I3C4, SIG_DESC_SET(SCU438, 23)); -+SIG_EXPR_LIST_DECL_SEMG(AF24, I3C4SDA, I3C4, I3C4, SIG_DESC_SET(SCU438, 23), -+ SIG_DESC_CLEAR(SCU418, 11)); - SIG_EXPR_LIST_DECL_SESG(AF24, FSI2DATA, FSI2, SIG_DESC_SET(SCU4D8, 23)); - PIN_DECL_(AF24, SIG_EXPR_LIST_PTR(AF24, I3C4SDA), - SIG_EXPR_LIST_PTR(AF24, FSI2DATA)); -@@ -1636,6 +1735,23 @@ - FUNC_DECL_1(USB2BD, USBB); - FUNC_DECL_1(USB2BH, USBB); - -+/* bit19: Enable RC-L DMA mode -+ * bit23: Enable RC-L DMA decode -+ */ -+#define PCIERC0_DESC { ASPEED_IP_SCU, SCUC24, GENMASK(23, 19), 0x1f, 0 } -+ -+#define A7 256 -+SIG_EXPR_LIST_DECL_SESG(A7, PERST, PCIERC0, SIG_DESC_SET(SCU040, 21), -+ SIG_DESC_CLEAR(SCU0C8, 6), PCIERC0_DESC); -+PIN_DECL_(A7, SIG_EXPR_LIST_PTR(A7, PERST)); -+FUNC_GROUP_DECL(PCIERC0, A7); -+ -+#define D7 257 -+SIG_EXPR_LIST_DECL_SESG(D7, RCRST, PCIERC1, SIG_DESC_SET(SCU040, 19), -+ SIG_DESC_SET(SCU500, 24)); -+PIN_DECL_(D7, SIG_EXPR_LIST_PTR(D7, RCRST)); -+FUNC_GROUP_DECL(PCIERC1, D7); -+ - /* Pins, groups and functions are sort(1):ed alphabetically for sanity */ - - static struct pinctrl_pin_desc aspeed_g6_pins[ASPEED_G6_NR_PINS] = { -@@ -1658,6 +1774,7 @@ - ASPEED_PINCTRL_PIN(A3), - ASPEED_PINCTRL_PIN(A4), - ASPEED_PINCTRL_PIN(A6), -+ ASPEED_PINCTRL_PIN(A7), - ASPEED_PINCTRL_PIN(AA11), - ASPEED_PINCTRL_PIN(AA12), - ASPEED_PINCTRL_PIN(AA16), -@@ -1806,6 +1923,7 @@ - ASPEED_PINCTRL_PIN(D4), - ASPEED_PINCTRL_PIN(D5), - ASPEED_PINCTRL_PIN(D6), -+ ASPEED_PINCTRL_PIN(D7), - ASPEED_PINCTRL_PIN(E1), - ASPEED_PINCTRL_PIN(E11), - ASPEED_PINCTRL_PIN(E12), -@@ -1921,6 +2039,7 @@ - ASPEED_PINCTRL_GROUP(FSI2), - ASPEED_PINCTRL_GROUP(FWSPIABR), - ASPEED_PINCTRL_GROUP(FWSPID), -+ ASPEED_PINCTRL_GROUP(FWQSPID), - ASPEED_PINCTRL_GROUP(FWQSPI), - ASPEED_PINCTRL_GROUP(FWSPIWP), - ASPEED_PINCTRL_GROUP(GPIT0), -@@ -1958,6 +2077,16 @@ - ASPEED_PINCTRL_GROUP(I2C7), - ASPEED_PINCTRL_GROUP(I2C8), - ASPEED_PINCTRL_GROUP(I2C9), -+ ASPEED_PINCTRL_GROUP(SI2C1), -+ ASPEED_PINCTRL_GROUP(SI2C2), -+ ASPEED_PINCTRL_GROUP(SI2C3), -+ ASPEED_PINCTRL_GROUP(SI2C4), -+ ASPEED_PINCTRL_GROUP(SI2C5), -+ ASPEED_PINCTRL_GROUP(SI2C6), -+ ASPEED_PINCTRL_GROUP(SI2C7), -+ ASPEED_PINCTRL_GROUP(SI2C8), -+ ASPEED_PINCTRL_GROUP(SI2C9), -+ ASPEED_PINCTRL_GROUP(SI2C10), - ASPEED_PINCTRL_GROUP(I3C1), - ASPEED_PINCTRL_GROUP(I3C2), - ASPEED_PINCTRL_GROUP(I3C3), -@@ -2073,6 +2202,8 @@ - ASPEED_PINCTRL_GROUP(SALT9G1), - ASPEED_PINCTRL_GROUP(SD1), - ASPEED_PINCTRL_GROUP(SD2), -+ ASPEED_PINCTRL_GROUP(PCIERC0), -+ ASPEED_PINCTRL_GROUP(PCIERC1), - ASPEED_PINCTRL_GROUP(EMMCG1), - ASPEED_PINCTRL_GROUP(EMMCG4), - ASPEED_PINCTRL_GROUP(EMMCG8), -@@ -2132,6 +2263,7 @@ - ASPEED_PINCTRL_GROUP(USBA), - ASPEED_PINCTRL_GROUP(USBB), - ASPEED_PINCTRL_GROUP(VB), -+ ASPEED_PINCTRL_GROUP(VPA), - ASPEED_PINCTRL_GROUP(VGAHS), - ASPEED_PINCTRL_GROUP(VGAVS), - ASPEED_PINCTRL_GROUP(WDTRST1), -@@ -2200,6 +2332,16 @@ - ASPEED_PINCTRL_FUNC(I2C7), - ASPEED_PINCTRL_FUNC(I2C8), - ASPEED_PINCTRL_FUNC(I2C9), -+ ASPEED_PINCTRL_FUNC(SI2C1), -+ ASPEED_PINCTRL_FUNC(SI2C2), -+ ASPEED_PINCTRL_FUNC(SI2C3), -+ ASPEED_PINCTRL_FUNC(SI2C4), -+ ASPEED_PINCTRL_FUNC(SI2C5), -+ ASPEED_PINCTRL_FUNC(SI2C6), -+ ASPEED_PINCTRL_FUNC(SI2C7), -+ ASPEED_PINCTRL_FUNC(SI2C8), -+ ASPEED_PINCTRL_FUNC(SI2C9), -+ ASPEED_PINCTRL_FUNC(SI2C10), - ASPEED_PINCTRL_FUNC(I3C1), - ASPEED_PINCTRL_FUNC(I3C2), - ASPEED_PINCTRL_FUNC(I3C3), -@@ -2314,6 +2456,8 @@ - ASPEED_PINCTRL_FUNC(SPI2), - ASPEED_PINCTRL_FUNC(SPI2CS1), - ASPEED_PINCTRL_FUNC(SPI2CS2), -+ ASPEED_PINCTRL_FUNC(PCIERC0), -+ ASPEED_PINCTRL_FUNC(PCIERC1), - ASPEED_PINCTRL_FUNC(TACH0), - ASPEED_PINCTRL_FUNC(TACH1), - ASPEED_PINCTRL_FUNC(TACH10), -@@ -2354,6 +2498,7 @@ - ASPEED_PINCTRL_FUNC(USB2BD), - ASPEED_PINCTRL_FUNC(USB2BH), - ASPEED_PINCTRL_FUNC(VB), -+ ASPEED_PINCTRL_FUNC(VPA), - ASPEED_PINCTRL_FUNC(VGAHS), - ASPEED_PINCTRL_FUNC(VGAVS), - ASPEED_PINCTRL_FUNC(WDTRST1), -@@ -2607,6 +2752,10 @@ - { PIN_CONFIG_DRIVE_STRENGTH, { AB8, AB8 }, SCU454, GENMASK(27, 26)}, - /* LAD0 */ - { PIN_CONFIG_DRIVE_STRENGTH, { AB7, AB7 }, SCU454, GENMASK(25, 24)}, -+ /* GPIOF */ -+ { PIN_CONFIG_DRIVE_STRENGTH, { D22, A23 }, SCU458, GENMASK(9, 8)}, -+ /* GPIOG */ -+ { PIN_CONFIG_DRIVE_STRENGTH, { E21, B21 }, SCU458, GENMASK(11, 10)}, - - /* MAC3 */ - { PIN_CONFIG_POWER_SOURCE, { H24, E26 }, SCU458, BIT_MASK(4)}, -@@ -2615,6 +2764,11 @@ - { PIN_CONFIG_POWER_SOURCE, { F24, B24 }, SCU458, BIT_MASK(5)}, - { PIN_CONFIG_DRIVE_STRENGTH, { F24, B24 }, SCU458, GENMASK(3, 2)}, - -+ /* GPIOJ */ -+ { PIN_CONFIG_DRIVE_STRENGTH, { B20, A20 }, SCU650, BIT_MASK(12)}, -+ { PIN_CONFIG_DRIVE_STRENGTH, { E19, D20 }, SCU650, BIT_MASK(13)}, -+ { PIN_CONFIG_DRIVE_STRENGTH, { C19, A19 }, SCU650, BIT_MASK(14)}, -+ { PIN_CONFIG_DRIVE_STRENGTH, { C20, D19 }, SCU650, BIT_MASK(15)}, - /* GPIO18E */ - ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, Y1, Y4, SCU40C, 4), - 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 2026-04-08 18:03:48.322705101 +0000 -@@ -0,0 +1,1156 @@ -+// SPDX-License-Identifier: GPL-2.0 -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "pinctrl-aspeed.h" -+ -+#define SCU3B0 0x3B0 /* USB Controller Register */ -+#define SCU3B4 0x3B4 /* USB Controller Lock Register */ -+#define SCU3B8 0x3B8 /* USB Controller Secure Register #1 */ -+#define SCU3BC 0x3BC /* USB Controller Secure Register #2 */ -+#define SCU3C0 0x3C0 /* USB Controller Secure Register #3 */ -+#define SCU400 0x400 /* Multi-function Pin Control #1 */ -+#define SCU404 0x404 /* Multi-function Pin Control #2 */ -+#define SCU408 0x408 /* Multi-function Pin Control #3 */ -+#define SCU40C 0x40C /* Multi-function Pin Control #4 */ -+#define SCU410 0x410 /* Multi-function Pin Control #5 */ -+#define SCU414 0x414 /* Multi-function Pin Control #6 */ -+#define SCU418 0x418 /* Multi-function Pin Control #7 */ -+#define SCU41C 0x41C /* Multi-function Pin Control #8 */ -+#define SCU420 0x420 /* Multi-function Pin Control #9 */ -+#define SCU424 0x424 /* Multi-function Pin Control #10 */ -+#define SCU428 0x428 /* Multi-function Pin Control #11 */ -+#define SCU42C 0x42C /* Multi-function Pin Control #12 */ -+#define SCU430 0x430 /* Multi-function Pin Control #13 */ -+#define SCU434 0x434 /* Multi-function Pin Control #14 */ -+#define SCU438 0x438 /* Multi-function Pin Control #15 */ -+#define SCU43C 0x43C /* Multi-function Pin Control #16 */ -+#define SCU440 0x440 /* Multi-function Pin Control #17 */ -+#define SCU444 0x444 /* Multi-function Pin Control #18 */ -+#define SCU448 0x448 /* Multi-function Pin Control #19 */ -+#define SCU44C 0x44C /* Multi-function Pin Control #20 */ -+#define SCU450 0x450 /* Multi-function Pin Control #21 */ -+#define SCU454 0x454 /* Multi-function Pin Control #22 */ -+#define SCU458 0x458 /* Multi-function Pin Control #23 */ -+#define SCU45C 0x45C /* Multi-function Pin Control #24 */ -+#define SCU460 0x460 /* Multi-function Pin Control #25 */ -+#define SCU464 0x464 /* Multi-function Pin Control #26 */ -+#define SCU468 0x468 /* Multi-function Pin Control #27 */ -+#define SCU46C 0x46C /* Multi-function Pin Control #28 */ -+#define SCU470 0x470 /* Multi-function Pin Control #29 */ -+#define SCU474 0x474 /* Multi-function Pin Control #30 */ -+#define SCU478 0x478 /* Multi-function Pin Control #31 */ -+#define SCU47C 0x47C -+#define SCU4A0 0x4A0 /* Voltage Selection */ -+#define SCU4C0 0x4C0 /* Driving Strength #0 A-I */ -+#define SCU4C4 0x4C4 /* Driving Strength #1 J-K */ -+#define SCU4C8 0x4C8 /* Driving Strength #2 L-M */ -+#define SCU4CC 0x4CC /* Driving Strength #3 N-O */ -+#define SCU4D0 0x4D0 /* Driving Strength #4 P-Q */ -+#define SCU4D4 0x4D4 /* Driving Strength #5 R-S */ -+#define SCU4D8 0x4D8 /* Driving Strength #6 T-U */ -+#define SCU4DC 0x4DC /* Driving Strength #7 W */ -+ -+#define SCU908 0x908 /* PCIe RC PERST Pin Control */ -+ -+enum { -+ D6, -+ B7, -+ A7, -+ C6, -+ B6, -+ A6, -+ C5, -+ D5, -+ L15, -+ H17, -+ L16, -+ K15, -+ K16, -+ K14, -+ J14, -+ J16, -+ J15, -+ G17, -+ F17, -+ D17, -+ C17, -+ H16, -+ B17, -+ E17, -+ A16, -+ B16, -+ H14, -+ A15, -+ G16, -+ F15, -+ H15, -+ D16, -+ M2, -+ M1, -+ M3, -+ M4, -+ N1, -+ N2, -+ N3, -+ L5, -+ P2, -+ P1, -+ N4, -+ N5, -+ HOLE0, -+ P3, -+ R1, -+ P4, -+ J2, -+ J1, -+ K4, -+ K2, -+ K3, -+ K1, -+ L4, -+ L2, -+ L1, -+ L3, -+ A14, -+ B14, -+ HOLE1, -+ HOLE2, -+ HOLE3, -+ HOLE4, -+ U15, -+ U16, -+ T17, -+ P12, -+ R13, -+ T15, -+ T16, -+ R12, -+ R14, -+ R17, -+ R15, -+ P13, -+ R16, -+ P14, -+ P17, -+ P16, -+ P15, -+ N17, -+ N14, -+ M17, -+ N15, -+ N16, -+ L17, -+ K17, -+ J17, -+ M14, -+ M15, -+ M16, -+ A4, -+ B5, -+ A5, -+ B4, -+ A10, -+ B9, -+ C7, -+ E8, -+ E7, -+ B8, -+ A9, -+ A8, -+ HOLE5, -+ HOLE6, -+ HOLE7, -+ HOLE8, -+ HOLE9, -+ HOLE10, -+ HOLE11, -+ HOLE12, -+ E13, -+ C12, -+ D12, -+ E12, -+ D13, -+ HOLE13, -+ B12, -+ HOLE14, -+ D15, -+ B13, -+ C14, -+ C13, -+ D14, -+ F13, -+ E14, -+ HOLE15, -+ HOLE16, -+ HOLE17, -+ B1, -+ C2, -+ D3, -+ C1, -+ E5, -+ HOLE18, -+ C11, -+ D11, -+ HOLE19, -+ HOLE20, -+ C10, -+ D10, -+ HOLE21, -+ HOLE22, -+ HOLE23, -+ HOLE24, -+ D9, -+ E9, -+ C9, -+ D8, -+ C8, -+ B11, -+ B10, -+ A12, -+ A11, -+ D7, -+ HOLE25, -+ HOLE26, -+ HOLE27, -+ HOLE28, -+ G2, -+ G1, -+ G4, -+ H3, -+ H2, -+ H1, -+ J4, -+ J3, -+ C4, -+ A2, -+ C3, -+ B2, -+ B3, -+ A3, -+ F2, -+ F1, -+ D2, -+ D1, -+ F4, -+ E4, -+ E2, -+ E1, -+ F3, -+ G5, -+ T4, -+ T3, -+ R5, -+ R6, -+ T2, -+ T5, -+ U2, -+ R7, -+ P9, -+ U4, -+ U5, -+ U6, -+ T7, -+ U7, -+ R10, -+ R11, -+ C16, -+ F16, -+ B15, -+ G15, -+ G14, -+ F14, -+ E15, -+ C15, -+}; -+ -+GROUP_DECL(TACH0, L15); -+GROUP_DECL(TACH1, H17); -+GROUP_DECL(TACH2, L16); -+GROUP_DECL(TACH3, K15); -+GROUP_DECL(TACH4, K16); -+GROUP_DECL(TACH5, K14); -+GROUP_DECL(TACH6, J14); -+GROUP_DECL(TACH7, J16); -+GROUP_DECL(TACH8, J15); -+GROUP_DECL(TACH9, G17); -+GROUP_DECL(TACH10, F17); -+GROUP_DECL(TACH11, D17); -+GROUP_DECL(TACH12, C17); -+GROUP_DECL(TACH13, H16); -+GROUP_DECL(TACH14, B17); -+GROUP_DECL(TACH15, E17); -+GROUP_DECL(PWM0, A16); -+GROUP_DECL(PWM1, B16); -+GROUP_DECL(PWM2, H14); -+GROUP_DECL(PWM3, A15); -+GROUP_DECL(PWM4, G16); -+GROUP_DECL(PWM5, F15); -+GROUP_DECL(PWM6, H15); -+GROUP_DECL(PWM7, D16); -+GROUP_DECL(PWM8, K4); -+GROUP_DECL(PWM9, K2); -+GROUP_DECL(PWM10, K3); -+GROUP_DECL(PWM11, K1); -+GROUP_DECL(PWM12, L4); -+GROUP_DECL(PWM13, L2); -+GROUP_DECL(PWM14, L1); -+GROUP_DECL(PWM15, L3); -+GROUP_DECL(ADC0, T4); -+GROUP_DECL(ADC1, T3); -+GROUP_DECL(ADC2, R5); -+GROUP_DECL(ADC3, R6); -+GROUP_DECL(ADC4, T2); -+GROUP_DECL(ADC5, T5); -+GROUP_DECL(ADC6, U2); -+GROUP_DECL(ADC7, R7); -+GROUP_DECL(ADC8, P9); -+GROUP_DECL(ADC9, U4); -+GROUP_DECL(ADC10, U5); -+GROUP_DECL(ADC11, U6); -+GROUP_DECL(ADC12, T7); -+GROUP_DECL(ADC13, U7); -+GROUP_DECL(ADC14, R10); -+GROUP_DECL(ADC15, R11); -+GROUP_DECL(SGPM1, F14, E15, A14, B14); -+GROUP_DECL(I2C0, G2, G1); -+GROUP_DECL(I2C1, G4, H3); -+GROUP_DECL(I2C2, H2, H1); -+GROUP_DECL(I2C3, J4, J3); -+GROUP_DECL(I2C4, C4, A2); -+GROUP_DECL(I2C5, C3, B2); -+GROUP_DECL(I2C6, B3, A3); -+GROUP_DECL(I2C7, F2, F1); -+GROUP_DECL(I2C8, D2, D1); -+GROUP_DECL(I2C9, F4, E4); -+GROUP_DECL(I2C10, E2, E1); -+GROUP_DECL(I2C11, F3, G5); -+GROUP_DECL(I2C12, J1, K2); -+GROUP_DECL(I2C13, K3, K1); -+GROUP_DECL(I2C14, L4, L2); -+GROUP_DECL(I2C15, L1, L3); -+GROUP_DECL(HVI3C12, U15, U16); -+GROUP_DECL(HVI3C13, T17, P12); -+GROUP_DECL(HVI3C14, R13, T15); -+GROUP_DECL(HVI3C15, T16, R12); -+GROUP_DECL(I3C4, R14, R17); -+GROUP_DECL(I3C5, R15, P13); -+GROUP_DECL(I3C6, R16, P14); -+GROUP_DECL(I3C7, P17, P16); -+GROUP_DECL(I3C8, P15, N17); -+GROUP_DECL(I3C9, N14, M17); -+GROUP_DECL(I3C10, N15, N16); -+GROUP_DECL(I3C11, L17, K17); -+GROUP_DECL(HVI3C0, J17, M14); -+GROUP_DECL(HVI3C1, M15, M16); -+GROUP_DECL(HVI3C2, A4, B5); -+GROUP_DECL(HVI3C3, A5, B4); -+GROUP_DECL(JTAGM, C2, D3, C1, E5); -+ -+static struct aspeed_pin_group aspeed_g7_ltpi_pingroups[] = { -+ ASPEED_PINCTRL_GROUP(TACH0), -+ ASPEED_PINCTRL_GROUP(TACH1), -+ ASPEED_PINCTRL_GROUP(TACH2), -+ ASPEED_PINCTRL_GROUP(TACH3), -+ ASPEED_PINCTRL_GROUP(TACH4), -+ ASPEED_PINCTRL_GROUP(TACH5), -+ ASPEED_PINCTRL_GROUP(TACH6), -+ ASPEED_PINCTRL_GROUP(TACH7), -+ ASPEED_PINCTRL_GROUP(TACH8), -+ ASPEED_PINCTRL_GROUP(TACH9), -+ ASPEED_PINCTRL_GROUP(TACH10), -+ ASPEED_PINCTRL_GROUP(TACH11), -+ ASPEED_PINCTRL_GROUP(TACH12), -+ ASPEED_PINCTRL_GROUP(TACH13), -+ ASPEED_PINCTRL_GROUP(TACH14), -+ ASPEED_PINCTRL_GROUP(TACH15), -+ ASPEED_PINCTRL_GROUP(PWM0), -+ ASPEED_PINCTRL_GROUP(PWM1), -+ ASPEED_PINCTRL_GROUP(PWM2), -+ ASPEED_PINCTRL_GROUP(PWM3), -+ ASPEED_PINCTRL_GROUP(PWM4), -+ ASPEED_PINCTRL_GROUP(PWM5), -+ ASPEED_PINCTRL_GROUP(PWM6), -+ ASPEED_PINCTRL_GROUP(PWM7), -+ ASPEED_PINCTRL_GROUP(PWM8), -+ ASPEED_PINCTRL_GROUP(PWM9), -+ ASPEED_PINCTRL_GROUP(PWM10), -+ ASPEED_PINCTRL_GROUP(PWM11), -+ ASPEED_PINCTRL_GROUP(PWM12), -+ ASPEED_PINCTRL_GROUP(PWM13), -+ ASPEED_PINCTRL_GROUP(PWM14), -+ ASPEED_PINCTRL_GROUP(PWM15), -+ ASPEED_PINCTRL_GROUP(ADC0), -+ ASPEED_PINCTRL_GROUP(ADC1), -+ ASPEED_PINCTRL_GROUP(ADC2), -+ ASPEED_PINCTRL_GROUP(ADC3), -+ ASPEED_PINCTRL_GROUP(ADC4), -+ ASPEED_PINCTRL_GROUP(ADC5), -+ ASPEED_PINCTRL_GROUP(ADC6), -+ ASPEED_PINCTRL_GROUP(ADC7), -+ ASPEED_PINCTRL_GROUP(ADC8), -+ ASPEED_PINCTRL_GROUP(ADC9), -+ ASPEED_PINCTRL_GROUP(ADC10), -+ ASPEED_PINCTRL_GROUP(ADC11), -+ ASPEED_PINCTRL_GROUP(ADC12), -+ ASPEED_PINCTRL_GROUP(ADC13), -+ ASPEED_PINCTRL_GROUP(ADC14), -+ ASPEED_PINCTRL_GROUP(ADC15), -+ ASPEED_PINCTRL_GROUP(I2C0), -+ ASPEED_PINCTRL_GROUP(I2C1), -+ ASPEED_PINCTRL_GROUP(I2C2), -+ ASPEED_PINCTRL_GROUP(I2C3), -+ ASPEED_PINCTRL_GROUP(I2C4), -+ ASPEED_PINCTRL_GROUP(I2C5), -+ ASPEED_PINCTRL_GROUP(I2C6), -+ ASPEED_PINCTRL_GROUP(I2C7), -+ ASPEED_PINCTRL_GROUP(I2C8), -+ ASPEED_PINCTRL_GROUP(I2C9), -+ ASPEED_PINCTRL_GROUP(I2C10), -+ ASPEED_PINCTRL_GROUP(I2C11), -+ ASPEED_PINCTRL_GROUP(I2C12), -+ ASPEED_PINCTRL_GROUP(I2C13), -+ ASPEED_PINCTRL_GROUP(I2C14), -+ ASPEED_PINCTRL_GROUP(I2C15), -+ ASPEED_PINCTRL_GROUP(HVI3C12), -+ ASPEED_PINCTRL_GROUP(HVI3C13), -+ ASPEED_PINCTRL_GROUP(HVI3C14), -+ ASPEED_PINCTRL_GROUP(HVI3C15), -+ ASPEED_PINCTRL_GROUP(I3C4), -+ ASPEED_PINCTRL_GROUP(I3C5), -+ ASPEED_PINCTRL_GROUP(I3C6), -+ ASPEED_PINCTRL_GROUP(I3C7), -+ ASPEED_PINCTRL_GROUP(I3C8), -+ ASPEED_PINCTRL_GROUP(I3C9), -+ ASPEED_PINCTRL_GROUP(I3C10), -+ ASPEED_PINCTRL_GROUP(I3C11), -+ ASPEED_PINCTRL_GROUP(HVI3C0), -+ ASPEED_PINCTRL_GROUP(HVI3C1), -+ ASPEED_PINCTRL_GROUP(HVI3C2), -+ ASPEED_PINCTRL_GROUP(HVI3C3), -+ ASPEED_PINCTRL_GROUP(JTAGM), -+ ASPEED_PINCTRL_GROUP(SGPM1), -+}; -+ -+FUNC_DECL_(TACH0, "TACH0"); -+FUNC_DECL_(TACH1, "TACH1"); -+FUNC_DECL_(TACH2, "TACH2"); -+FUNC_DECL_(TACH3, "TACH3"); -+FUNC_DECL_(TACH4, "TACH4"); -+FUNC_DECL_(TACH5, "TACH5"); -+FUNC_DECL_(TACH6, "TACH6"); -+FUNC_DECL_(TACH7, "TACH7"); -+FUNC_DECL_(TACH8, "TACH8"); -+FUNC_DECL_(TACH9, "TACH9"); -+FUNC_DECL_(TACH10, "TACH10"); -+FUNC_DECL_(TACH11, "TACH11"); -+FUNC_DECL_(TACH12, "TACH12"); -+FUNC_DECL_(TACH13, "TACH13"); -+FUNC_DECL_(TACH14, "TACH14"); -+FUNC_DECL_(TACH15, "TACH15"); -+FUNC_DECL_(PWM0, "PWM0"); -+FUNC_DECL_(PWM1, "PWM1"); -+FUNC_DECL_(PWM2, "PWM2"); -+FUNC_DECL_(PWM3, "PWM3"); -+FUNC_DECL_(PWM4, "PWM4"); -+FUNC_DECL_(PWM5, "PWM5"); -+FUNC_DECL_(PWM6, "PWM6"); -+FUNC_DECL_(PWM7, "PWM7"); -+FUNC_DECL_(PWM8, "PWM8"); -+FUNC_DECL_(PWM9, "PWM9"); -+FUNC_DECL_(PWM10, "PWM10"); -+FUNC_DECL_(PWM11, "PWM11"); -+FUNC_DECL_(PWM12, "PWM12"); -+FUNC_DECL_(PWM13, "PWM13"); -+FUNC_DECL_(PWM14, "PWM14"); -+FUNC_DECL_(PWM15, "PWM15"); -+FUNC_DECL_(ADC0, "ADC0"); -+FUNC_DECL_(ADC1, "ADC1"); -+FUNC_DECL_(ADC2, "ADC2"); -+FUNC_DECL_(ADC3, "ADC3"); -+FUNC_DECL_(ADC4, "ADC4"); -+FUNC_DECL_(ADC5, "ADC5"); -+FUNC_DECL_(ADC6, "ADC6"); -+FUNC_DECL_(ADC7, "ADC7"); -+FUNC_DECL_(ADC8, "ADC8"); -+FUNC_DECL_(ADC9, "ADC9"); -+FUNC_DECL_(ADC10, "ADC10"); -+FUNC_DECL_(ADC11, "ADC11"); -+FUNC_DECL_(ADC12, "ADC12"); -+FUNC_DECL_(ADC13, "ADC13"); -+FUNC_DECL_(ADC14, "ADC14"); -+FUNC_DECL_(ADC15, "ADC15"); -+FUNC_DECL_(I2C0, "I2C0"); -+FUNC_DECL_(I2C1, "I2C1"); -+FUNC_DECL_(I2C2, "I2C2"); -+FUNC_DECL_(I2C3, "I2C3"); -+FUNC_DECL_(I2C4, "I2C4"); -+FUNC_DECL_(I2C5, "I2C5"); -+FUNC_DECL_(I2C6, "I2C6"); -+FUNC_DECL_(I2C7, "I2C7"); -+FUNC_DECL_(I2C8, "I2C8"); -+FUNC_DECL_(I2C9, "I2C9"); -+FUNC_DECL_(I2C10, "I2C10"); -+FUNC_DECL_(I2C11, "I2C11"); -+FUNC_DECL_(I2C12, "I2C12"); -+FUNC_DECL_(I2C13, "I2C13"); -+FUNC_DECL_(I2C14, "I2C14"); -+FUNC_DECL_(I2C15, "I2C15"); -+FUNC_DECL_(I3C12, "HVI3C12"); -+FUNC_DECL_(I3C13, "HVI3C13"); -+FUNC_DECL_(I3C14, "HVI3C14"); -+FUNC_DECL_(I3C15, "HVI3C15"); -+FUNC_DECL_(I3C4, "I3C4"); -+FUNC_DECL_(I3C5, "I3C5"); -+FUNC_DECL_(I3C6, "I3C6"); -+FUNC_DECL_(I3C7, "I3C7"); -+FUNC_DECL_(I3C8, "I3C8"); -+FUNC_DECL_(I3C9, "I3C9"); -+FUNC_DECL_(I3C10, "I3C10"); -+FUNC_DECL_(I3C11, "I3C11"); -+FUNC_DECL_(I3C0, "HVI3C0"); -+FUNC_DECL_(I3C1, "HVI3C1"); -+FUNC_DECL_(I3C2, "HVI3C2"); -+FUNC_DECL_(I3C3, "HVI3C3"); -+FUNC_DECL_(JTAGM, "JTAGM"); -+FUNC_DECL_(SGPM1, "SGPM1"); -+ -+static struct aspeed_pin_function aspeed_g7_ltpi_funcs[] = { -+ ASPEED_PINCTRL_FUNC(TACH0), -+ ASPEED_PINCTRL_FUNC(TACH1), -+ ASPEED_PINCTRL_FUNC(TACH2), -+ ASPEED_PINCTRL_FUNC(TACH3), -+ ASPEED_PINCTRL_FUNC(TACH4), -+ ASPEED_PINCTRL_FUNC(TACH5), -+ ASPEED_PINCTRL_FUNC(TACH6), -+ ASPEED_PINCTRL_FUNC(TACH7), -+ ASPEED_PINCTRL_FUNC(TACH8), -+ ASPEED_PINCTRL_FUNC(TACH9), -+ ASPEED_PINCTRL_FUNC(TACH10), -+ ASPEED_PINCTRL_FUNC(TACH11), -+ ASPEED_PINCTRL_FUNC(TACH12), -+ ASPEED_PINCTRL_FUNC(TACH13), -+ ASPEED_PINCTRL_FUNC(TACH14), -+ ASPEED_PINCTRL_FUNC(TACH15), -+ ASPEED_PINCTRL_FUNC(PWM0), -+ ASPEED_PINCTRL_FUNC(PWM1), -+ ASPEED_PINCTRL_FUNC(PWM2), -+ ASPEED_PINCTRL_FUNC(PWM3), -+ ASPEED_PINCTRL_FUNC(PWM4), -+ ASPEED_PINCTRL_FUNC(PWM5), -+ ASPEED_PINCTRL_FUNC(PWM6), -+ ASPEED_PINCTRL_FUNC(PWM7), -+ ASPEED_PINCTRL_FUNC(PWM8), -+ ASPEED_PINCTRL_FUNC(PWM9), -+ ASPEED_PINCTRL_FUNC(PWM10), -+ ASPEED_PINCTRL_FUNC(PWM11), -+ ASPEED_PINCTRL_FUNC(PWM12), -+ ASPEED_PINCTRL_FUNC(PWM13), -+ ASPEED_PINCTRL_FUNC(PWM14), -+ ASPEED_PINCTRL_FUNC(PWM15), -+ ASPEED_PINCTRL_FUNC(ADC0), -+ ASPEED_PINCTRL_FUNC(ADC1), -+ ASPEED_PINCTRL_FUNC(ADC2), -+ ASPEED_PINCTRL_FUNC(ADC3), -+ ASPEED_PINCTRL_FUNC(ADC4), -+ ASPEED_PINCTRL_FUNC(ADC5), -+ ASPEED_PINCTRL_FUNC(ADC6), -+ ASPEED_PINCTRL_FUNC(ADC7), -+ ASPEED_PINCTRL_FUNC(ADC8), -+ ASPEED_PINCTRL_FUNC(ADC9), -+ ASPEED_PINCTRL_FUNC(ADC10), -+ ASPEED_PINCTRL_FUNC(ADC11), -+ ASPEED_PINCTRL_FUNC(ADC12), -+ ASPEED_PINCTRL_FUNC(ADC13), -+ ASPEED_PINCTRL_FUNC(ADC14), -+ ASPEED_PINCTRL_FUNC(ADC15), -+ ASPEED_PINCTRL_FUNC(I2C0), -+ ASPEED_PINCTRL_FUNC(I2C1), -+ ASPEED_PINCTRL_FUNC(I2C2), -+ ASPEED_PINCTRL_FUNC(I2C3), -+ ASPEED_PINCTRL_FUNC(I2C4), -+ ASPEED_PINCTRL_FUNC(I2C5), -+ ASPEED_PINCTRL_FUNC(I2C6), -+ ASPEED_PINCTRL_FUNC(I2C7), -+ ASPEED_PINCTRL_FUNC(I2C8), -+ ASPEED_PINCTRL_FUNC(I2C9), -+ ASPEED_PINCTRL_FUNC(I2C10), -+ ASPEED_PINCTRL_FUNC(I2C11), -+ ASPEED_PINCTRL_FUNC(I2C12), -+ ASPEED_PINCTRL_FUNC(I2C13), -+ ASPEED_PINCTRL_FUNC(I2C14), -+ ASPEED_PINCTRL_FUNC(I2C15), -+ ASPEED_PINCTRL_FUNC(I3C12), -+ ASPEED_PINCTRL_FUNC(I3C13), -+ ASPEED_PINCTRL_FUNC(I3C14), -+ ASPEED_PINCTRL_FUNC(I3C15), -+ ASPEED_PINCTRL_FUNC(I3C4), -+ ASPEED_PINCTRL_FUNC(I3C5), -+ ASPEED_PINCTRL_FUNC(I3C6), -+ ASPEED_PINCTRL_FUNC(I3C7), -+ ASPEED_PINCTRL_FUNC(I3C8), -+ ASPEED_PINCTRL_FUNC(I3C9), -+ ASPEED_PINCTRL_FUNC(I3C10), -+ ASPEED_PINCTRL_FUNC(I3C11), -+ ASPEED_PINCTRL_FUNC(I3C0), -+ ASPEED_PINCTRL_FUNC(I3C1), -+ ASPEED_PINCTRL_FUNC(I3C2), -+ ASPEED_PINCTRL_FUNC(I3C3), -+ ASPEED_PINCTRL_FUNC(JTAGM), -+ ASPEED_PINCTRL_FUNC(SGPM1), -+}; -+ -+/* number, name, drv_data */ -+static const struct pinctrl_pin_desc aspeed_g7_ltpi_pins[] = { -+ PINCTRL_PIN(D6, "D6"), -+ PINCTRL_PIN(B7, "B7"), -+ PINCTRL_PIN(A7, "A7"), -+ PINCTRL_PIN(C6, "C6"), -+ PINCTRL_PIN(B6, "B6"), -+ PINCTRL_PIN(A6, "A6"), -+ PINCTRL_PIN(C5, "C5"), -+ PINCTRL_PIN(D5, "D5"), -+ PINCTRL_PIN(L15, "L15"), -+ PINCTRL_PIN(H17, "H17"), -+ PINCTRL_PIN(L16, "L16"), -+ PINCTRL_PIN(K15, "K15"), -+ PINCTRL_PIN(K16, "K16"), -+ PINCTRL_PIN(K14, "K14"), -+ PINCTRL_PIN(J14, "J14"), -+ PINCTRL_PIN(J16, "J16"), -+ PINCTRL_PIN(J15, "J15"), -+ PINCTRL_PIN(G17, "G17"), -+ PINCTRL_PIN(F17, "F17"), -+ PINCTRL_PIN(D17, "D17"), -+ PINCTRL_PIN(C17, "C17"), -+ PINCTRL_PIN(H16, "H16"), -+ PINCTRL_PIN(B17, "B17"), -+ PINCTRL_PIN(E17, "E17"), -+ PINCTRL_PIN(A16, "A16"), -+ PINCTRL_PIN(B16, "B16"), -+ PINCTRL_PIN(H14, "H14"), -+ PINCTRL_PIN(A15, "A15"), -+ PINCTRL_PIN(G16, "G16"), -+ PINCTRL_PIN(F15, "F15"), -+ PINCTRL_PIN(H15, "H15"), -+ PINCTRL_PIN(D16, "D16"), -+ PINCTRL_PIN(M2, "M2"), -+ PINCTRL_PIN(M1, "M1"), -+ PINCTRL_PIN(M3, "M3"), -+ PINCTRL_PIN(M4, "M4"), -+ PINCTRL_PIN(N1, "N1"), -+ PINCTRL_PIN(N2, "N2"), -+ PINCTRL_PIN(N3, "N3"), -+ PINCTRL_PIN(L5, "L5"), -+ PINCTRL_PIN(P2, "P2"), -+ PINCTRL_PIN(P1, "P1"), -+ PINCTRL_PIN(N4, "N4"), -+ PINCTRL_PIN(N5, "N5"), -+ PINCTRL_PIN(HOLE0, "HOLE0"), -+ PINCTRL_PIN(P3, "P3"), -+ PINCTRL_PIN(R1, "R1"), -+ PINCTRL_PIN(P4, "P4"), -+ PINCTRL_PIN(J2, "J2"), -+ PINCTRL_PIN(J1, "J1"), -+ PINCTRL_PIN(K4, "K4"), -+ PINCTRL_PIN(K2, "K2"), -+ PINCTRL_PIN(K3, "K3"), -+ PINCTRL_PIN(K1, "K1"), -+ PINCTRL_PIN(L4, "L4"), -+ PINCTRL_PIN(L2, "L2"), -+ PINCTRL_PIN(L1, "L1"), -+ PINCTRL_PIN(L3, "L3"), -+ PINCTRL_PIN(A14, "A14"), -+ PINCTRL_PIN(B14, "B14"), -+ PINCTRL_PIN(HOLE1, "HOLE1"), -+ PINCTRL_PIN(HOLE2, "HOLE2"), -+ PINCTRL_PIN(HOLE3, "HOLE3"), -+ PINCTRL_PIN(HOLE4, "HOLE4"), -+ PINCTRL_PIN(U15, "U15"), -+ PINCTRL_PIN(U16, "U16"), -+ PINCTRL_PIN(T17, "T17"), -+ PINCTRL_PIN(P12, "P12"), -+ PINCTRL_PIN(R13, "R13"), -+ PINCTRL_PIN(T15, "T15"), -+ PINCTRL_PIN(T16, "T16"), -+ PINCTRL_PIN(R12, "R12"), -+ PINCTRL_PIN(R14, "R14"), -+ PINCTRL_PIN(R17, "R17"), -+ PINCTRL_PIN(R15, "R15"), -+ PINCTRL_PIN(P13, "P13"), -+ PINCTRL_PIN(R16, "R16"), -+ PINCTRL_PIN(P14, "P14"), -+ PINCTRL_PIN(P17, "P17"), -+ PINCTRL_PIN(P16, "P16"), -+ PINCTRL_PIN(P15, "P15"), -+ PINCTRL_PIN(N17, "N17"), -+ PINCTRL_PIN(N14, "N14"), -+ PINCTRL_PIN(M17, "M17"), -+ PINCTRL_PIN(N15, "N15"), -+ PINCTRL_PIN(N16, "N16"), -+ PINCTRL_PIN(L17, "L17"), -+ PINCTRL_PIN(K17, "K17"), -+ PINCTRL_PIN(J17, "J17"), -+ PINCTRL_PIN(M14, "M14"), -+ PINCTRL_PIN(M15, "M15"), -+ PINCTRL_PIN(M16, "M16"), -+ PINCTRL_PIN(A4, "A4"), -+ PINCTRL_PIN(B5, "B5"), -+ PINCTRL_PIN(A5, "A5"), -+ PINCTRL_PIN(B4, "B4"), -+ PINCTRL_PIN(A10, "A10"), -+ PINCTRL_PIN(B9, "B9"), -+ PINCTRL_PIN(C7, "C7"), -+ PINCTRL_PIN(E8, "E8"), -+ PINCTRL_PIN(E7, "E7"), -+ PINCTRL_PIN(B8, "B8"), -+ PINCTRL_PIN(A9, "A9"), -+ PINCTRL_PIN(A8, "A8"), -+ PINCTRL_PIN(HOLE5, "HOLE5"), -+ PINCTRL_PIN(HOLE6, "HOLE6"), -+ PINCTRL_PIN(HOLE7, "HOLE7"), -+ PINCTRL_PIN(HOLE8, "HOLE8"), -+ PINCTRL_PIN(HOLE9, "HOLE9"), -+ PINCTRL_PIN(HOLE10, "HOLE10"), -+ PINCTRL_PIN(HOLE11, "HOLE11"), -+ PINCTRL_PIN(HOLE12, "HOLE12"), -+ PINCTRL_PIN(E13, "E13"), -+ PINCTRL_PIN(C12, "C12"), -+ PINCTRL_PIN(D12, "D12"), -+ PINCTRL_PIN(E12, "E12"), -+ PINCTRL_PIN(D13, "D13"), -+ PINCTRL_PIN(HOLE13, "HOLE13"), -+ PINCTRL_PIN(B12, "B12"), -+ PINCTRL_PIN(HOLE14, "HOLE14"), -+ PINCTRL_PIN(D15, "D15"), -+ PINCTRL_PIN(B13, "B13"), -+ PINCTRL_PIN(C14, "C14"), -+ PINCTRL_PIN(C13, "C13"), -+ PINCTRL_PIN(D14, "D14"), -+ PINCTRL_PIN(F13, "F13"), -+ PINCTRL_PIN(E14, "E14"), -+ PINCTRL_PIN(HOLE15, "HOLE15"), -+ PINCTRL_PIN(HOLE16, "HOLE16"), -+ PINCTRL_PIN(HOLE17, "HOLE17"), -+ PINCTRL_PIN(B1, "B1"), -+ PINCTRL_PIN(C2, "C2"), -+ PINCTRL_PIN(D3, "D3"), -+ 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(D9, "D9"), -+ PINCTRL_PIN(E9, "E9"), -+ PINCTRL_PIN(C9, "C9"), -+ PINCTRL_PIN(D8, "D8"), -+ PINCTRL_PIN(C8, "C8"), -+ PINCTRL_PIN(B11, "B11"), -+ PINCTRL_PIN(B10, "B10"), -+ 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(G2, "G2"), -+ PINCTRL_PIN(G1, "G1"), -+ PINCTRL_PIN(G4, "G4"), -+ PINCTRL_PIN(H3, "H3"), -+ PINCTRL_PIN(H2, "H2"), -+ PINCTRL_PIN(H1, "H1"), -+ PINCTRL_PIN(J4, "J4"), -+ PINCTRL_PIN(J3, "J3"), -+ PINCTRL_PIN(C4, "C4"), -+ PINCTRL_PIN(A2, "A2"), -+ PINCTRL_PIN(C3, "C3"), -+ PINCTRL_PIN(B2, "B2"), -+ PINCTRL_PIN(B3, "B3"), -+ PINCTRL_PIN(A3, "A3"), -+ PINCTRL_PIN(F2, "F2"), -+ PINCTRL_PIN(F1, "F1"), -+ PINCTRL_PIN(D2, "D2"), -+ PINCTRL_PIN(D1, "D1"), -+ PINCTRL_PIN(F4, "F4"), -+ PINCTRL_PIN(E4, "E4"), -+ PINCTRL_PIN(E2, "E2"), -+ PINCTRL_PIN(E1, "E1"), -+ PINCTRL_PIN(F3, "F3"), -+ PINCTRL_PIN(G5, "G5"), -+ PINCTRL_PIN(T4, "T4"), -+ PINCTRL_PIN(T3, "T3"), -+ PINCTRL_PIN(R5, "R5"), -+ PINCTRL_PIN(R6, "R6"), -+ PINCTRL_PIN(T2, "T2"), -+ PINCTRL_PIN(T5, "T5"), -+ PINCTRL_PIN(U2, "U2"), -+ PINCTRL_PIN(R7, "R7"), -+ PINCTRL_PIN(P9, "P9"), -+ PINCTRL_PIN(U4, "U4"), -+ PINCTRL_PIN(U5, "U5"), -+ PINCTRL_PIN(U6, "U6"), -+ PINCTRL_PIN(T7, "T7"), -+ PINCTRL_PIN(U7, "U7"), -+ PINCTRL_PIN(R10, "R10"), -+ PINCTRL_PIN(R11, "R11"), -+ PINCTRL_PIN(C16, "C16"), -+ PINCTRL_PIN(F16, "F16"), -+ PINCTRL_PIN(B15, "B15"), -+ PINCTRL_PIN(G15, "G15"), -+ PINCTRL_PIN(G14, "G14"), -+ PINCTRL_PIN(F14, "F14"), -+ PINCTRL_PIN(E15, "E15"), -+ PINCTRL_PIN(C15, "C15"), -+}; -+ -+FUNCFG_DESCL(L15, PIN_CFG(TACH0, SCU404, GENMASK(2, 0), 1)); -+FUNCFG_DESCL(H17, PIN_CFG(TACH1, SCU404, GENMASK(6, 4), (1 << 4))); -+FUNCFG_DESCL(L16, PIN_CFG(TACH2, SCU404, GENMASK(10, 8), (1 << 8))); -+FUNCFG_DESCL(K15, PIN_CFG(TACH3, SCU404, GENMASK(14, 12), (1 << 12))); -+FUNCFG_DESCL(K16, PIN_CFG(TACH4, SCU404, GENMASK(18, 16), (1 << 16))); -+FUNCFG_DESCL(K14, PIN_CFG(TACH5, SCU404, GENMASK(22, 20), (1 << 20))); -+FUNCFG_DESCL(J14, PIN_CFG(TACH6, SCU404, GENMASK(26, 24), (1 << 24))); -+FUNCFG_DESCL(J16, PIN_CFG(TACH7, SCU404, GENMASK(30, 28), (1 << 28))); -+FUNCFG_DESCL(J15, PIN_CFG(TACH8, SCU408, GENMASK(2, 0), 1)); -+FUNCFG_DESCL(G17, PIN_CFG(TACH9, SCU408, GENMASK(6, 4), (1 << 4))); -+FUNCFG_DESCL(F17, PIN_CFG(TACH10, SCU408, GENMASK(10, 8), (1 << 8))); -+FUNCFG_DESCL(D17, PIN_CFG(TACH11, SCU408, GENMASK(14, 12), (1 << 12))); -+FUNCFG_DESCL(C17, PIN_CFG(TACH12, SCU408, GENMASK(18, 16), (1 << 16))); -+FUNCFG_DESCL(H16, PIN_CFG(TACH13, SCU408, GENMASK(22, 20), (1 << 20))); -+FUNCFG_DESCL(B17, PIN_CFG(TACH14, SCU408, GENMASK(26, 24), (1 << 24))); -+FUNCFG_DESCL(E17, PIN_CFG(TACH15, SCU408, GENMASK(30, 28), (1 << 28))); -+FUNCFG_DESCL(A16, PIN_CFG(PWM0, SCU40C, GENMASK(2, 0), 1)); -+FUNCFG_DESCL(B16, PIN_CFG(PWM1, SCU40C, GENMASK(6, 4), (1 << 4))); -+FUNCFG_DESCL(H14, PIN_CFG(PWM2, SCU40C, GENMASK(10, 8), (1 << 8))); -+FUNCFG_DESCL(A15, PIN_CFG(PWM3, SCU40C, GENMASK(14, 12), (1 << 12))); -+FUNCFG_DESCL(G16, PIN_CFG(PWM4, SCU40C, GENMASK(18, 16), (1 << 16))); -+FUNCFG_DESCL(F15, PIN_CFG(PWM5, SCU40C, GENMASK(22, 20), (1 << 20))); -+FUNCFG_DESCL(H15, PIN_CFG(PWM6, SCU40C, GENMASK(26, 24), (1 << 24))); -+FUNCFG_DESCL(D16, PIN_CFG(PWM7, SCU40C, GENMASK(30, 28), (1 << 28))); -+FUNCFG_DESCL(J1, PIN_CFG(I2C12, SCU418, GENMASK(6, 4), (4 << 4))); -+FUNCFG_DESCL(K4, PIN_CFG(PWM8, SCU418, GENMASK(10, 8), (3 << 8))); -+FUNCFG_DESCL(K2, PIN_CFG(PWM9, SCU418, GENMASK(14, 12), (3 << 12)), -+ PIN_CFG(I2C12, SCU418, GENMASK(14, 12), (4 << 12))); -+FUNCFG_DESCL(K3, PIN_CFG(PWM10, SCU418, GENMASK(18, 16), (3 << 16)), -+ PIN_CFG(I2C13, SCU418, GENMASK(18, 16), (4 << 16))); -+FUNCFG_DESCL(K1, PIN_CFG(PWM11, SCU418, GENMASK(22, 20), (3 << 20)), -+ PIN_CFG(I2C13, SCU418, GENMASK(22, 20), (4 << 20))); -+FUNCFG_DESCL(L4, PIN_CFG(PWM12, SCU418, GENMASK(26, 24), (3 << 24)), -+ PIN_CFG(I2C14, SCU418, GENMASK(26, 24), (4 << 24))); -+FUNCFG_DESCL(L2, PIN_CFG(PWM13, SCU418, GENMASK(30, 28), (3 << 28)), -+ PIN_CFG(I2C14, SCU418, GENMASK(30, 28), (4 << 28))); -+FUNCFG_DESCL(L1, PIN_CFG(I2C15, SCU41C, GENMASK(2, 0), 2), -+ PIN_CFG(PWM14, SCU41C, GENMASK(2, 0), 3)); -+FUNCFG_DESCL(L3, PIN_CFG(I2C15, SCU41C, GENMASK(6, 4), (2 << 4)), -+ PIN_CFG(PWM15, SCU41C, GENMASK(6, 4), (3 << 4))); -+FUNCFG_DESCL(A14, PIN_CFG(SGPM1, SCU41C, GENMASK(10, 8), (1 << 8))); -+FUNCFG_DESCL(B14, PIN_CFG(SGPM1, SCU41C, GENMASK(14, 12), (1 << 12))); -+FUNCFG_DESCL(U15, PIN_CFG(HVI3C12, SCU420, GENMASK(2, 0), 1)); -+FUNCFG_DESCL(U16, PIN_CFG(HVI3C12, SCU420, GENMASK(6, 4), (1 << 4))); -+FUNCFG_DESCL(T17, PIN_CFG(HVI3C13, SCU420, GENMASK(10, 8), (1 << 8))); -+FUNCFG_DESCL(P12, PIN_CFG(HVI3C13, SCU420, GENMASK(14, 12), (1 << 12))); -+FUNCFG_DESCL(R13, PIN_CFG(HVI3C14, SCU420, GENMASK(18, 16), (1 << 16))); -+FUNCFG_DESCL(T15, PIN_CFG(HVI3C14, SCU420, GENMASK(22, 20), (1 << 20))); -+FUNCFG_DESCL(T16, PIN_CFG(HVI3C15, SCU420, GENMASK(26, 24), (1 << 24))); -+FUNCFG_DESCL(R12, PIN_CFG(HVI3C15, SCU420, GENMASK(30, 28), (1 << 28))); -+FUNCFG_DESCL(R14, PIN_CFG(I3C4, SCU424, GENMASK(2, 0), 1)); -+FUNCFG_DESCL(R17, PIN_CFG(I3C4, SCU424, GENMASK(6, 4), (1 << 4))); -+FUNCFG_DESCL(R15, PIN_CFG(I3C5, SCU424, GENMASK(10, 8), (1 << 8))); -+FUNCFG_DESCL(P13, PIN_CFG(I3C5, SCU424, GENMASK(14, 12), (1 << 12))); -+FUNCFG_DESCL(R16, PIN_CFG(I3C6, SCU424, GENMASK(18, 16), (1 << 16))); -+FUNCFG_DESCL(P14, PIN_CFG(I3C6, SCU424, GENMASK(22, 20), (1 << 20))); -+FUNCFG_DESCL(P17, PIN_CFG(I3C7, SCU424, GENMASK(26, 24), (1 << 24))); -+FUNCFG_DESCL(P16, PIN_CFG(I3C7, SCU424, GENMASK(30, 28), (1 << 28))); -+FUNCFG_DESCL(P15, PIN_CFG(I3C8, SCU428, GENMASK(2, 0), 1)); -+FUNCFG_DESCL(N17, PIN_CFG(I3C8, SCU428, GENMASK(6, 4), (1 << 4))); -+FUNCFG_DESCL(N14, PIN_CFG(I3C9, SCU428, GENMASK(10, 8), (1 << 8))); -+FUNCFG_DESCL(M17, PIN_CFG(I3C9, SCU428, GENMASK(14, 12), (1 << 12))); -+FUNCFG_DESCL(N15, PIN_CFG(I3C10, SCU428, GENMASK(18, 16), (1 << 16))); -+FUNCFG_DESCL(N16, PIN_CFG(I3C10, SCU428, GENMASK(22, 20), (1 << 20))); -+FUNCFG_DESCL(L17, PIN_CFG(I3C11, SCU428, GENMASK(26, 24), (1 << 24))); -+FUNCFG_DESCL(K17, PIN_CFG(I3C11, SCU428, GENMASK(30, 28), (1 << 28))); -+FUNCFG_DESCL(J17, PIN_CFG(HVI3C0, SCU42C, GENMASK(2, 0), 1)); -+FUNCFG_DESCL(M14, PIN_CFG(HVI3C0, SCU42C, GENMASK(6, 4), (1 << 4))); -+FUNCFG_DESCL(M15, PIN_CFG(HVI3C1, SCU42C, GENMASK(10, 8), (1 << 8))); -+FUNCFG_DESCL(M16, PIN_CFG(HVI3C1, SCU42C, GENMASK(14, 12), (1 << 12))); -+FUNCFG_DESCL(A4, PIN_CFG(HVI3C2, SCU42C, GENMASK(18, 16), (1 << 16))); -+FUNCFG_DESCL(B5, PIN_CFG(HVI3C2, SCU42C, GENMASK(22, 20), (1 << 20))); -+FUNCFG_DESCL(A5, PIN_CFG(HVI3C3, SCU42C, GENMASK(26, 24), (1 << 24))); -+FUNCFG_DESCL(B4, PIN_CFG(HVI3C3, SCU42C, GENMASK(30, 28), (1 << 28))); -+FUNCFG_DESCL(C2, PIN_CFG(JTAGM, SCU440, GENMASK(14, 12), (1 << 12))); -+FUNCFG_DESCL(D3, PIN_CFG(JTAGM, SCU440, GENMASK(18, 16), (1 << 16))); -+FUNCFG_DESCL(C1, PIN_CFG(JTAGM, SCU440, GENMASK(22, 20), (1 << 20))); -+FUNCFG_DESCL(E5, PIN_CFG(JTAGM, SCU440, GENMASK(26, 24), (1 << 24))); -+FUNCFG_DESCL(G2, PIN_CFG(I2C0, SCU454, GENMASK(2, 0), 1)); -+FUNCFG_DESCL(G1, PIN_CFG(I2C0, SCU454, GENMASK(6, 4), (1 << 4))); -+FUNCFG_DESCL(G4, PIN_CFG(I2C1, SCU454, GENMASK(10, 8), (1 << 8))); -+FUNCFG_DESCL(H3, PIN_CFG(I2C1, SCU454, GENMASK(14, 12), (1 << 12))); -+FUNCFG_DESCL(H2, PIN_CFG(I2C2, SCU454, GENMASK(18, 16), (1 << 16))); -+FUNCFG_DESCL(H1, PIN_CFG(I2C2, SCU454, GENMASK(22, 20), (1 << 20))); -+FUNCFG_DESCL(J4, PIN_CFG(I2C3, SCU454, GENMASK(26, 24), (1 << 24))); -+FUNCFG_DESCL(J3, PIN_CFG(I2C3, SCU454, GENMASK(30, 28), (1 << 28))); -+FUNCFG_DESCL(C4, PIN_CFG(I2C4, SCU458, GENMASK(2, 0), 1)); -+FUNCFG_DESCL(A2, PIN_CFG(I2C4, SCU458, GENMASK(6, 4), (1 << 4))); -+FUNCFG_DESCL(C3, PIN_CFG(I2C5, SCU458, GENMASK(10, 8), (1 << 8))); -+FUNCFG_DESCL(B2, PIN_CFG(I2C5, SCU458, GENMASK(14, 12), (1 << 12))); -+FUNCFG_DESCL(B3, PIN_CFG(I2C6, SCU458, GENMASK(18, 16), (1 << 16))); -+FUNCFG_DESCL(A3, PIN_CFG(I2C6, SCU458, GENMASK(22, 20), (1 << 20))); -+FUNCFG_DESCL(F2, PIN_CFG(I2C7, SCU458, GENMASK(26, 24), (1 << 24))); -+FUNCFG_DESCL(F1, PIN_CFG(I2C7, SCU458, GENMASK(30, 28), (1 << 28))); -+FUNCFG_DESCL(D2, PIN_CFG(I2C8, SCU45C, GENMASK(2, 0), 1)); -+FUNCFG_DESCL(D1, PIN_CFG(I2C8, SCU45C, GENMASK(6, 4), (1 << 4))); -+FUNCFG_DESCL(F4, PIN_CFG(I2C9, SCU45C, GENMASK(10, 8), (1 << 8))); -+FUNCFG_DESCL(E4, PIN_CFG(I2C9, SCU45C, GENMASK(14, 12), (1 << 12))); -+FUNCFG_DESCL(E2, PIN_CFG(I2C10, SCU45C, GENMASK(18, 16), (1 << 16))); -+FUNCFG_DESCL(E1, PIN_CFG(I2C10, SCU45C, GENMASK(22, 20), (1 << 20))); -+FUNCFG_DESCL(F3, PIN_CFG(I2C11, SCU45C, GENMASK(26, 24), (1 << 24))); -+FUNCFG_DESCL(G5, PIN_CFG(I2C11, SCU45C, GENMASK(30, 28), (1 << 28))); -+FUNCFG_DESCL(T4, PIN_CFG(ADC0, SCU460, GENMASK(2, 0), 0)); -+FUNCFG_DESCL(T3, PIN_CFG(ADC1, SCU460, GENMASK(6, 4), 0)); -+FUNCFG_DESCL(R5, PIN_CFG(ADC2, SCU460, GENMASK(10, 8), 0)); -+FUNCFG_DESCL(R6, PIN_CFG(ADC3, SCU460, GENMASK(14, 12), 0)); -+FUNCFG_DESCL(T2, PIN_CFG(ADC4, SCU460, GENMASK(18, 16), 0)); -+FUNCFG_DESCL(T5, PIN_CFG(ADC5, SCU460, GENMASK(22, 20), 0)); -+FUNCFG_DESCL(U2, PIN_CFG(ADC6, SCU460, GENMASK(26, 24), 0)); -+FUNCFG_DESCL(R7, PIN_CFG(ADC7, SCU460, GENMASK(30, 28), 0)); -+FUNCFG_DESCL(P9, PIN_CFG(ADC8, SCU464, GENMASK(2, 0), 0)); -+FUNCFG_DESCL(U4, PIN_CFG(ADC9, SCU464, GENMASK(6, 4), 0)); -+FUNCFG_DESCL(U5, PIN_CFG(ADC10, SCU464, GENMASK(10, 8), 0)); -+FUNCFG_DESCL(U6, PIN_CFG(ADC11, SCU464, GENMASK(14, 12), 0)); -+FUNCFG_DESCL(T7, PIN_CFG(ADC12, SCU464, GENMASK(18, 16), 0)); -+FUNCFG_DESCL(U7, PIN_CFG(ADC13, SCU464, GENMASK(22, 20), 0)); -+FUNCFG_DESCL(R10, PIN_CFG(ADC14, SCU464, GENMASK(26, 24), 0)); -+FUNCFG_DESCL(R11, PIN_CFG(ADC15, SCU464, GENMASK(30, 28), 0)); -+FUNCFG_DESCL(F14, PIN_CFG(SGPM1, SCU468, GENMASK(22, 20), (1 << 20))); -+FUNCFG_DESCL(E15, PIN_CFG(SGPM1, SCU468, GENMASK(26, 24), (1 << 24))); -+ -+static const struct aspeed_g7_pincfg pin_cfg[] = { -+ PINCFG_PIN(L15), -+ PINCFG_PIN(H17), -+ PINCFG_PIN(L16), -+ PINCFG_PIN(K15), -+ PINCFG_PIN(K16), -+ PINCFG_PIN(K14), -+ PINCFG_PIN(J14), -+ PINCFG_PIN(J16), -+ PINCFG_PIN(J15), -+ PINCFG_PIN(G17), -+ PINCFG_PIN(F17), -+ PINCFG_PIN(D17), -+ PINCFG_PIN(C17), -+ PINCFG_PIN(H16), -+ PINCFG_PIN(B17), -+ PINCFG_PIN(E17), -+ PINCFG_PIN(A16), -+ PINCFG_PIN(B16), -+ PINCFG_PIN(H14), -+ PINCFG_PIN(A15), -+ PINCFG_PIN(G16), -+ PINCFG_PIN(F15), -+ PINCFG_PIN(H15), -+ PINCFG_PIN(D16), -+ PINCFG_PIN(J1), -+ PINCFG_PIN(K4), -+ PINCFG_PIN(K2), -+ PINCFG_PIN(K3), -+ PINCFG_PIN(K1), -+ PINCFG_PIN(L4), -+ PINCFG_PIN(L2), -+ PINCFG_PIN(L1), -+ PINCFG_PIN(L3), -+ PINCFG_PIN(A14), -+ PINCFG_PIN(B14), -+ PINCFG_PIN(U15), -+ PINCFG_PIN(U16), -+ PINCFG_PIN(T17), -+ PINCFG_PIN(P12), -+ PINCFG_PIN(R13), -+ PINCFG_PIN(T15), -+ PINCFG_PIN(T16), -+ PINCFG_PIN(R12), -+ PINCFG_PIN(R14), -+ PINCFG_PIN(R17), -+ PINCFG_PIN(R15), -+ PINCFG_PIN(P13), -+ PINCFG_PIN(R16), -+ PINCFG_PIN(P14), -+ PINCFG_PIN(P17), -+ PINCFG_PIN(P16), -+ PINCFG_PIN(P15), -+ PINCFG_PIN(N17), -+ PINCFG_PIN(N14), -+ PINCFG_PIN(M17), -+ PINCFG_PIN(N15), -+ PINCFG_PIN(N16), -+ PINCFG_PIN(L17), -+ PINCFG_PIN(K17), -+ PINCFG_PIN(J17), -+ PINCFG_PIN(M14), -+ PINCFG_PIN(M15), -+ PINCFG_PIN(M16), -+ PINCFG_PIN(A4), -+ PINCFG_PIN(B5), -+ PINCFG_PIN(A5), -+ PINCFG_PIN(B4), -+ PINCFG_PIN(C2), -+ PINCFG_PIN(D3), -+ PINCFG_PIN(C1), -+ PINCFG_PIN(E5), -+ PINCFG_PIN(G2), -+ PINCFG_PIN(G1), -+ PINCFG_PIN(G4), -+ PINCFG_PIN(H3), -+ PINCFG_PIN(H2), -+ PINCFG_PIN(H1), -+ PINCFG_PIN(J4), -+ PINCFG_PIN(J3), -+ PINCFG_PIN(C4), -+ PINCFG_PIN(A2), -+ PINCFG_PIN(C3), -+ PINCFG_PIN(B2), -+ PINCFG_PIN(B3), -+ PINCFG_PIN(A3), -+ PINCFG_PIN(F2), -+ PINCFG_PIN(F1), -+ PINCFG_PIN(D2), -+ PINCFG_PIN(D1), -+ PINCFG_PIN(F4), -+ PINCFG_PIN(E4), -+ PINCFG_PIN(E2), -+ PINCFG_PIN(E1), -+ PINCFG_PIN(F3), -+ PINCFG_PIN(G5), -+ PINCFG_PIN(T4), -+ PINCFG_PIN(T3), -+ PINCFG_PIN(R5), -+ PINCFG_PIN(R6), -+ PINCFG_PIN(T2), -+ PINCFG_PIN(T5), -+ PINCFG_PIN(U2), -+ PINCFG_PIN(R7), -+ PINCFG_PIN(P9), -+ PINCFG_PIN(U4), -+ PINCFG_PIN(U5), -+ PINCFG_PIN(U6), -+ PINCFG_PIN(T7), -+ PINCFG_PIN(U7), -+ PINCFG_PIN(R10), -+ PINCFG_PIN(R11), -+ PINCFG_PIN(F14), -+ PINCFG_PIN(E15), -+}; -+ -+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) -+{ -+ return pinconf_generic_dt_node_to_map(pctldev, np_config, map, num_maps, -+ PIN_MAP_TYPE_INVALID); -+} -+ -+static void aspeed_g7_ltpi_dt_free_map(struct pinctrl_dev *pctldev, -+ struct pinctrl_map *map, u32 num_maps) -+{ -+ kfree(map); -+} -+ -+static const struct pinctrl_ops aspeed_g7_ltpi_pinctrl_ops = { -+ .get_groups_count = aspeed_pinctrl_get_groups_count, -+ .get_group_name = aspeed_pinctrl_get_group_name, -+ .get_group_pins = aspeed_pinctrl_get_group_pins, -+ .pin_dbg_show = aspeed_pinctrl_pin_dbg_show, -+ .dt_node_to_map = aspeed_g7_ltpi_dt_node_to_map, -+ .dt_free_map = aspeed_g7_ltpi_dt_free_map, -+}; -+ -+static const struct pinmux_ops aspeed_g7_ltpi_pinmux_ops = { -+ .get_functions_count = aspeed_pinmux_get_fn_count, -+ .get_function_name = aspeed_pinmux_get_fn_name, -+ .get_function_groups = aspeed_pinmux_get_fn_groups, -+ .set_mux = aspeed_g7_pinmux_set_mux, -+ .gpio_request_enable = aspeed_g7_gpio_request_enable, -+ .strict = true, -+}; -+ -+static const struct pinconf_ops aspeed_g7_ltpi_pinconf_ops = { -+ .is_generic = true, -+ .pin_config_get = aspeed_pin_config_get, -+ .pin_config_set = aspeed_pin_config_set, -+ .pin_config_group_get = aspeed_pin_config_group_get, -+ .pin_config_group_set = aspeed_pin_config_group_set, -+}; -+ -+/* pinctrl_desc */ -+static struct pinctrl_desc aspeed_g7_ltpi_pinctrl_desc = { -+ .name = "aspeed-g7-ltpi-pinctrl", -+ .pins = aspeed_g7_ltpi_pins, -+ .npins = ARRAY_SIZE(aspeed_g7_ltpi_pins), -+ .pctlops = &aspeed_g7_ltpi_pinctrl_ops, -+ .pmxops = &aspeed_g7_ltpi_pinmux_ops, -+ .confops = &aspeed_g7_ltpi_pinconf_ops, -+ .owner = THIS_MODULE, -+}; -+ -+static int aspeed_g7_ltpi_pinctrl_probe(struct platform_device *pdev) -+{ -+ struct aspeed_pinctrl_data *ltpi_pinctrl_data; -+ -+ ltpi_pinctrl_data = devm_kzalloc(&pdev->dev, sizeof(*ltpi_pinctrl_data), -+ GFP_KERNEL); -+ if (!ltpi_pinctrl_data) -+ return -ENOMEM; -+ -+ ltpi_pinctrl_data->pins = aspeed_g7_ltpi_pins; -+ ltpi_pinctrl_data->npins = ARRAY_SIZE(aspeed_g7_ltpi_pins); -+ ltpi_pinctrl_data->pinmux.groups = aspeed_g7_ltpi_pingroups; -+ ltpi_pinctrl_data->pinmux.ngroups = ARRAY_SIZE(aspeed_g7_ltpi_pingroups); -+ ltpi_pinctrl_data->pinmux.functions = aspeed_g7_ltpi_funcs; -+ 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); -+ -+ return aspeed_pinctrl_probe(pdev, &aspeed_g7_ltpi_pinctrl_desc, ltpi_pinctrl_data); -+} -+ -+static const struct of_device_id aspeed_g7_ltpi_pinctrl_match[] = { -+ { .compatible = "aspeed,ast1700-pinctrl" }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, aspeed_g7_ltpi_pinctrl_match); -+ -+static struct platform_driver aspeed_g7_ltpi_pinctrl_driver = { -+ .probe = aspeed_g7_ltpi_pinctrl_probe, -+ .driver = { -+ .name = "aspeed-g7-ltpi-pinctrl", -+ .of_match_table = aspeed_g7_ltpi_pinctrl_match, -+ .suppress_bind_attrs = true, -+ }, -+}; -+ -+static int __init aspeed_g7_ltpi_pinctrl_register(void) -+{ -+ return platform_driver_register(&aspeed_g7_ltpi_pinctrl_driver); -+} -+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 2026-04-08 18:03:48.322705101 +0000 -@@ -0,0 +1,503 @@ -+// SPDX-License-Identifier: GPL-2.0 -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "pinctrl-aspeed.h" -+#include "../pinctrl-utils.h" -+ -+#define SCU200 0x200 /* System Reset Control #1 */ -+ -+#define SCU400 0x400 /* Multi-function Pin Control #1 */ -+#define SCU404 0x404 /* Multi-function Pin Control #2 */ -+#define SCU408 0x408 /* Multi-function Pin Control #3 */ -+#define SCU40C 0x40C /* Multi-function Pin Control #3 */ -+#define SCU410 0x410 /* USB Multi-function Control Register */ -+#define SCU414 0x414 /* VGA Function Control Register */ -+ -+#define SCU480 0x480 /* GPIO18A0 IO Control Register */ -+#define SCU484 0x484 /* GPIO18A1 IO Control Register */ -+#define SCU488 0x488 /* GPIO18A2 IO Control Register */ -+#define SCU48C 0x48c /* GPIO18A3 IO Control Register */ -+#define SCU490 0x490 /* GPIO18A4 IO Control Register */ -+#define SCU494 0x494 /* GPIO18A5 IO Control Register */ -+#define SCU498 0x498 /* GPIO18A6 IO Control Register */ -+#define SCU49C 0x49c /* GPIO18A7 IO Control Register */ -+#define SCU4A0 0x4A0 /* GPIO18B0 IO Control Register */ -+#define SCU4A4 0x4A4 /* GPIO18B1 IO Control Register */ -+#define SCU4A8 0x4A8 /* GPIO18B2 IO Control Register */ -+#define SCU4AC 0x4AC /* GPIO18B3 IO Control Register */ -+ -+enum { -+ AC14, -+ AE15, -+ AD14, -+ AE14, -+ AF14, -+ AB13, -+ AB14, -+ AF15, -+ AF13, -+ AC13, -+ AD13, -+ AE13, -+ PORTA_U3, // SCU410[1:0] -+ PORTA_U2, // SCU410[3:2] -+ PORTB_U3, // SCU410[5:4] -+ PORTB_U2, // SCU410[7:6] -+ PORTA_U3_XHCI, // SCU410[9] -+ PORTA_U2_XHCI, // SCU410[9] -+ PORTB_U3_XHCI, // SCU410[10] -+ PORTB_U2_XHCI, // SCU410[10] -+ PORTA_MODE, // SCU410[25:24] -+ PORTB_MODE, // SCU410[29:28] -+ PORTA_U2_PHY, -+ PORTA_U3_PHY, -+ PORTB_U2_PHY, -+ PORTB_U3_PHY, -+ JTAG_PORT, -+ PCIERC0_PERST, -+ PCIERC1_PERST, -+}; -+ -+GROUP_DECL(EMMCG1, AC14, AE15, AD14); -+GROUP_DECL(EMMCG4, AC14, AE15, AD14, AE14, AF14, AB13); -+GROUP_DECL(EMMCG8, AC14, AE15, AD14, AE14, AF14, AB13, AF13, AC13, AD13, AE13); -+GROUP_DECL(EMMCWPN, AF15); -+GROUP_DECL(EMMCCDN, AB14); -+GROUP_DECL(VGADDC, AD13, AE13); -+GROUP_DECL(VB1, AC14, AE15, AD14, AE14); -+GROUP_DECL(VB0, AF15, AB14, AF13, AC13); -+//USB3A -+//xhci: BMC/PCIE, vHub/PHY/EXT port -+GROUP_DECL(USB3AXHD, PORTA_U3, PORTA_U3_XHCI); -+GROUP_DECL(USB3AXHPD, PORTA_U3, PORTA_U3_XHCI); -+GROUP_DECL(USB3AXH, PORTA_U3, PORTA_U3_XHCI, PORTA_U3_PHY); -+GROUP_DECL(USB3AXHP, PORTA_U3, PORTA_U3_XHCI, PORTA_U3_PHY); -+GROUP_DECL(USB3AXH2B, PORTA_U3, PORTA_U3_XHCI, PORTB_U3_PHY); -+GROUP_DECL(USB3AXHP2B, PORTA_U3, PORTA_U3_XHCI, PORTB_U3_PHY); -+ -+//USB2A -+//xhci: BMC/PCIE, vHub/PHY/EXT port -+GROUP_DECL(USB2AXHD1, PORTA_U2, PORTA_U2_XHCI); -+GROUP_DECL(USB2AXHPD1, PORTA_U2, PORTA_U2_XHCI); -+GROUP_DECL(USB2AXH, PORTA_U2, PORTA_U2_XHCI, PORTA_U2_PHY); -+GROUP_DECL(USB2AXHP, PORTA_U2, PORTA_U2_XHCI, PORTA_U2_PHY); -+GROUP_DECL(USB2AXH2B, PORTA_U2, PORTA_U2_XHCI, PORTB_U2_PHY); -+GROUP_DECL(USB2AXHP2B, PORTA_U2, PORTA_U2_XHCI, PORTB_U2_PHY); -+// vhub to phy -+GROUP_DECL(USB2AD1, PORTA_U2, PORTA_U2_PHY); -+//ehci -+GROUP_DECL(USB2AHPD0, PORTA_MODE); -+GROUP_DECL(USB2AH, PORTA_MODE, PORTA_U2_PHY); -+GROUP_DECL(USB2AHP, PORTA_MODE, PORTA_U2_PHY); -+GROUP_DECL(USB2AD0, PORTA_MODE, PORTA_U2_PHY); -+ -+//USB3B -+//xhci: BMC/PCIE, vHub/PHY/EXT port -+GROUP_DECL(USB3BXHD, PORTB_U3, PORTB_U3_XHCI); -+GROUP_DECL(USB3BXHPD, PORTB_U3, PORTB_U3_XHCI); -+GROUP_DECL(USB3BXH, PORTB_U3, PORTB_U3_XHCI, PORTB_U3_PHY); -+GROUP_DECL(USB3BXHP, PORTB_U3, PORTB_U3_XHCI, PORTB_U3_PHY); -+GROUP_DECL(USB3BXH2A, PORTB_U3, PORTB_U3_XHCI, PORTA_U3_PHY); -+GROUP_DECL(USB3BXHP2A, PORTB_U3, PORTB_U3_XHCI, PORTA_U3_PHY); -+ -+//USB2B -+//xhci: BMC/PCIE, vHub/PHY/EXT port -+GROUP_DECL(USB2BXHD1, PORTB_U2, PORTB_U2_XHCI); -+GROUP_DECL(USB2BXHPD1, PORTB_U2, PORTB_U2_XHCI); -+GROUP_DECL(USB2BXH, PORTB_U2, PORTB_U2_XHCI, PORTB_U2_PHY); -+GROUP_DECL(USB2BXHP, PORTB_U2, PORTB_U2_XHCI, PORTB_U2_PHY); -+GROUP_DECL(USB2BXH2A, PORTB_U2, PORTB_U2_XHCI, PORTA_U2_PHY); -+GROUP_DECL(USB2BXHP2A, PORTB_U2, PORTB_U2_XHCI, PORTA_U2_PHY); -+// vhub to phy -+GROUP_DECL(USB2BD1, PORTB_U2, PORTB_U2_PHY); -+//ehci -+GROUP_DECL(USB2BHPD0, PORTB_MODE); -+GROUP_DECL(USB2BH, PORTB_MODE, PORTB_U2_PHY); -+GROUP_DECL(USB2BHP, PORTB_MODE, PORTB_U2_PHY); -+GROUP_DECL(USB2BD0, PORTB_MODE, PORTB_U2_PHY); -+//JTAG port -+GROUP_DECL(PSP, JTAG_PORT); -+GROUP_DECL(SSP, JTAG_PORT); -+GROUP_DECL(TSP, JTAG_PORT); -+GROUP_DECL(DDR, JTAG_PORT); -+GROUP_DECL(USB3A, JTAG_PORT); -+GROUP_DECL(USB3B, JTAG_PORT); -+GROUP_DECL(PCIEA, JTAG_PORT); -+GROUP_DECL(PCIEB, JTAG_PORT); -+GROUP_DECL(JTAGM0, JTAG_PORT); -+//PCIE RC PERST -+GROUP_DECL(PCIERC0PERST, PCIERC0_PERST); -+GROUP_DECL(PCIERC1PERST, PCIERC1_PERST); -+ -+static struct aspeed_pin_group aspeed_g7_soc0_pingroups[] = { -+ ASPEED_PINCTRL_GROUP(EMMCG1), -+ ASPEED_PINCTRL_GROUP(EMMCG4), -+ ASPEED_PINCTRL_GROUP(EMMCG8), -+ ASPEED_PINCTRL_GROUP(EMMCWPN), -+ ASPEED_PINCTRL_GROUP(EMMCCDN), -+ ASPEED_PINCTRL_GROUP(VGADDC), -+ ASPEED_PINCTRL_GROUP(VB1), -+ ASPEED_PINCTRL_GROUP(VB0), -+ ASPEED_PINCTRL_GROUP(USB3AXHD), -+ ASPEED_PINCTRL_GROUP(USB3AXHPD), -+ ASPEED_PINCTRL_GROUP(USB3AXH), -+ ASPEED_PINCTRL_GROUP(USB3AXHP), -+ ASPEED_PINCTRL_GROUP(USB3AXH2B), -+ ASPEED_PINCTRL_GROUP(USB3AXHP2B), -+ ASPEED_PINCTRL_GROUP(USB2AXHD1), -+ ASPEED_PINCTRL_GROUP(USB2AXHPD1), -+ ASPEED_PINCTRL_GROUP(USB2AXH), -+ ASPEED_PINCTRL_GROUP(USB2AXHP), -+ ASPEED_PINCTRL_GROUP(USB2AXH2B), -+ ASPEED_PINCTRL_GROUP(USB2AXHP2B), -+ ASPEED_PINCTRL_GROUP(USB2AD1), -+ ASPEED_PINCTRL_GROUP(USB2AHPD0), -+ ASPEED_PINCTRL_GROUP(USB2AH), -+ ASPEED_PINCTRL_GROUP(USB2AHP), -+ ASPEED_PINCTRL_GROUP(USB2AD0), -+ ASPEED_PINCTRL_GROUP(USB3BXHD), -+ ASPEED_PINCTRL_GROUP(USB3BXHPD), -+ ASPEED_PINCTRL_GROUP(USB3BXH), -+ ASPEED_PINCTRL_GROUP(USB3BXHP), -+ ASPEED_PINCTRL_GROUP(USB3BXH2A), -+ ASPEED_PINCTRL_GROUP(USB3BXHP2A), -+ ASPEED_PINCTRL_GROUP(USB2BXHD1), -+ ASPEED_PINCTRL_GROUP(USB2BXHPD1), -+ ASPEED_PINCTRL_GROUP(USB2BXH), -+ ASPEED_PINCTRL_GROUP(USB2BXHP), -+ ASPEED_PINCTRL_GROUP(USB2BXH2A), -+ ASPEED_PINCTRL_GROUP(USB2BXHP2A), -+ ASPEED_PINCTRL_GROUP(USB2BD1), -+ ASPEED_PINCTRL_GROUP(USB2BHPD0), -+ ASPEED_PINCTRL_GROUP(USB2BH), -+ ASPEED_PINCTRL_GROUP(USB2BHP), -+ ASPEED_PINCTRL_GROUP(USB2BD0), -+ ASPEED_PINCTRL_GROUP(PSP), -+ ASPEED_PINCTRL_GROUP(SSP), -+ ASPEED_PINCTRL_GROUP(TSP), -+ ASPEED_PINCTRL_GROUP(DDR), -+ ASPEED_PINCTRL_GROUP(USB3A), -+ ASPEED_PINCTRL_GROUP(USB3B), -+ ASPEED_PINCTRL_GROUP(PCIEA), -+ ASPEED_PINCTRL_GROUP(PCIEB), -+ ASPEED_PINCTRL_GROUP(JTAGM0), -+ ASPEED_PINCTRL_GROUP(PCIERC0PERST), -+ ASPEED_PINCTRL_GROUP(PCIERC1PERST), -+}; -+ -+FUNC_DECL_(EMMC, "EMMCG1", "EMMCG4", "EMMCG8", "EMMCWPN", "EMMCCDN"); -+FUNC_DECL_(VGADDC, "VGADDC"); -+FUNC_DECL_(VB, "VB0", "VB1"); -+FUNC_DECL_(USB3A, "USB3AXHD", "USB3AXHPD", "USB3AXH", "USB3AXHP", "USB3AXH2B", -+ "USB3AXHP2B"); -+FUNC_DECL_(USB2A, "USB2AXHD1", "USB2AXHPD1", "USB2AXH", "USB2AXHP", "USB2AXH2B", -+ "USB2AXHP2B", "USB2AD1", "USB2AHPD0", "USB2AH", "USB2AHP", -+ "USB2AD0"); -+FUNC_DECL_(USB3B, "USB3BXHD", "USB3BXHPD", "USB3BXH", "USB3BXHP", "USB3BXH2A", -+ "USB3BXHP2A"); -+FUNC_DECL_(USB2B, "USB2BXHD1", "USB2BXHPD1", "USB2BXH", "USB2BXHP", "USB2BXH2A", -+ "USB2BXHP2A", "USB2BD1", "USB2BHPD0", "USB2BH", "USB2BHP", -+ "USB2BD0"); -+FUNC_DECL_(JTAG0, "PSP", "SSP", "TSP", "DDR", "USB3A", "USB3B", -+ "PCIEA", "PCIEB", "JTAGM0"); -+FUNC_DECL_(PCIERC, "PCIERC0PERST", "PCIERC1PERST"); -+ -+static struct aspeed_pin_function aspeed_g7_soc0_funcs[] = { -+ ASPEED_PINCTRL_FUNC(EMMC), -+ ASPEED_PINCTRL_FUNC(VGADDC), -+ ASPEED_PINCTRL_FUNC(VB), -+ ASPEED_PINCTRL_FUNC(USB3A), -+ ASPEED_PINCTRL_FUNC(USB2A), -+ ASPEED_PINCTRL_FUNC(USB3B), -+ ASPEED_PINCTRL_FUNC(USB2B), -+ ASPEED_PINCTRL_FUNC(JTAG0), -+ ASPEED_PINCTRL_FUNC(PCIERC), -+}; -+ -+static const struct pinctrl_pin_desc aspeed_g7_soc0_pins[] = { -+ PINCTRL_PIN(AC14, "AC14"), -+ PINCTRL_PIN(AE15, "AE15"), -+ PINCTRL_PIN(AD14, "AD14"), -+ PINCTRL_PIN(AE14, "AE14"), -+ PINCTRL_PIN(AF14, "AF14"), -+ PINCTRL_PIN(AB13, "AB13"), -+ PINCTRL_PIN(AF15, "AF15"), -+ PINCTRL_PIN(AB14, "AB14"), -+ PINCTRL_PIN(AF13, "AF13"), -+ PINCTRL_PIN(AC13, "AC13"), -+ PINCTRL_PIN(AD13, "AD13"), -+ PINCTRL_PIN(AE13, "AE13"), -+ PINCTRL_PIN(PORTA_U3, "PORTA_U3"), -+ PINCTRL_PIN(PORTA_U2, "PORTA_U2"), -+ PINCTRL_PIN(PORTB_U3, "PORTB_U3"), -+ PINCTRL_PIN(PORTB_U2, "PORTB_U2"), -+ PINCTRL_PIN(PORTA_U3_XHCI, "PORTA_U3_XHCI"), -+ PINCTRL_PIN(PORTA_U2_XHCI, "PORTA_U2_XHCI"), -+ PINCTRL_PIN(PORTB_U3_XHCI, "PORTB_U3_XHCI"), -+ PINCTRL_PIN(PORTB_U2_XHCI, "PORTB_U2_XHCI"), -+ PINCTRL_PIN(PORTA_MODE, "PORTA_MODE"), -+ PINCTRL_PIN(PORTA_U3_PHY, "PORTA_U3_PHY"), -+ PINCTRL_PIN(PORTA_U2_PHY, "PORTA_U2_PHY"), -+ PINCTRL_PIN(PORTB_MODE, "PORTB_MODE"), -+ PINCTRL_PIN(PORTB_U3_PHY, "PORTB_U3_PHY"), -+ PINCTRL_PIN(PORTB_U2_PHY, "PORTB_U2_PHY"), -+ PINCTRL_PIN(JTAG_PORT, "JTAG_PORT"), -+ PINCTRL_PIN(PCIERC0_PERST, "PCIERC0_PERST"), -+ PINCTRL_PIN(PCIERC1_PERST, "PCIERC1_PERST"), -+}; -+ -+FUNCFG_DESCL(AC14, PIN_CFG(EMMCG1, SCU400, BIT_MASK(0), BIT(0)), -+ PIN_CFG(EMMCG4, SCU400, BIT_MASK(0), BIT(0)), -+ PIN_CFG(EMMCG8, SCU400, BIT_MASK(0), BIT(0)), -+ PIN_CFG(VB1, SCU404, BIT_MASK(0), BIT(0))); -+FUNCFG_DESCL(AE15, PIN_CFG(EMMCG1, SCU400, BIT_MASK(1), BIT(1)), -+ PIN_CFG(EMMCG4, SCU400, BIT_MASK(1), BIT(1)), -+ PIN_CFG(EMMCG8, SCU400, BIT_MASK(1), BIT(1)), -+ PIN_CFG(VB1, SCU404, BIT_MASK(1), BIT(1))); -+FUNCFG_DESCL(AD14, PIN_CFG(EMMCG1, SCU400, BIT_MASK(2), BIT(2)), -+ PIN_CFG(EMMCG4, SCU400, BIT_MASK(2), BIT(2)), -+ PIN_CFG(EMMCG8, SCU400, BIT_MASK(2), BIT(2)), -+ PIN_CFG(VB1, SCU404, BIT_MASK(2), BIT(2))); -+FUNCFG_DESCL(AE14, PIN_CFG(EMMCG4, SCU400, BIT_MASK(3), BIT(3)), -+ PIN_CFG(EMMCG8, SCU400, BIT_MASK(3), BIT(3)), -+ PIN_CFG(VB1, SCU404, BIT_MASK(3), BIT(3))); -+FUNCFG_DESCL(AF14, PIN_CFG(EMMCG4, SCU400, BIT_MASK(4), BIT(4)), -+ PIN_CFG(EMMCG8, SCU400, BIT_MASK(4), BIT(4))); -+FUNCFG_DESCL(AB13, PIN_CFG(EMMCG4, SCU400, BIT_MASK(5), BIT(5)), -+ PIN_CFG(EMMCG8, SCU400, BIT_MASK(5), BIT(5))); -+FUNCFG_DESCL(AB14, PIN_CFG(EMMCCDN, SCU400, BIT_MASK(6), BIT(6)), -+ PIN_CFG(VB0, SCU404, BIT_MASK(6), BIT(6))); -+FUNCFG_DESCL(AF15, PIN_CFG(EMMCWPN, SCU400, BIT_MASK(7), BIT(7)), -+ PIN_CFG(VB0, SCU404, BIT_MASK(7), BIT(7))); -+FUNCFG_DESCL(AF13, PIN_CFG(EMMCG8, SCU400, BIT_MASK(8), BIT(8)), -+ PIN_CFG(VB0, SCU404, BIT_MASK(8), BIT(8))); -+FUNCFG_DESCL(AC13, PIN_CFG(EMMCG8, SCU400, BIT_MASK(9), BIT(9)), -+ PIN_CFG(VB0, SCU404, BIT_MASK(9), BIT(9))); -+FUNCFG_DESCL(AD13, PIN_CFG(EMMCG8, SCU400, BIT_MASK(10), BIT(10)), -+ PIN_CFG(VGADDC, SCU404, BIT_MASK(10), BIT(10))); -+FUNCFG_DESCL(AE13, PIN_CFG(EMMCG8, SCU400, BIT_MASK(11), BIT(11)), -+ PIN_CFG(VGADDC, SCU404, BIT_MASK(11), BIT(11))); -+FUNCFG_DESCL(PORTA_U3, PIN_CFG(USB3AXHD, SCU410, GENMASK(1, 0), 0), -+ PIN_CFG(USB3AXHPD, SCU410, GENMASK(1, 0), 0), -+ PIN_CFG(USB3AXH, SCU410, GENMASK(1, 0), 2), -+ PIN_CFG(USB3AXHP, SCU410, GENMASK(1, 0), 2), -+ PIN_CFG(USB3AXH2B, SCU410, GENMASK(1, 0), 3), -+ PIN_CFG(USB3AXHP2B, SCU410, GENMASK(1, 0), 3)); -+FUNCFG_DESCL(PORTA_U2, PIN_CFG(USB2AXHD1, SCU410, GENMASK(3, 2), 0), -+ PIN_CFG(USB2AXHPD1, SCU410, GENMASK(3, 2), 0), -+ PIN_CFG(USB2AXH, SCU410, GENMASK(3, 2), 2 << 2), -+ PIN_CFG(USB2AXHP, SCU410, GENMASK(3, 2), 2 << 2), -+ PIN_CFG(USB2AXH2B, SCU410, GENMASK(3, 2), 3 << 2), -+ PIN_CFG(USB2AXHP2B, SCU410, GENMASK(3, 2), 3 << 2), -+ PIN_CFG(USB2AD1, SCU410, GENMASK(3, 2), 1 << 2)); -+FUNCFG_DESCL(PORTB_U3, PIN_CFG(USB3BXHD, SCU410, GENMASK(5, 4), 0), -+ PIN_CFG(USB3BXHPD, SCU410, GENMASK(5, 4), 0), -+ PIN_CFG(USB3BXH, SCU410, GENMASK(5, 4), 2 << 4), -+ PIN_CFG(USB3BXHP, SCU410, GENMASK(5, 4), 2 << 4), -+ PIN_CFG(USB3BXH2A, SCU410, GENMASK(5, 4), 3 << 4), -+ PIN_CFG(USB3BXHP2A, SCU410, GENMASK(5, 4), 3 << 4)); -+FUNCFG_DESCL(PORTB_U2, PIN_CFG(USB2BXHD1, SCU410, GENMASK(7, 6), 0), -+ PIN_CFG(USB2BXHPD1, SCU410, GENMASK(7, 6), 0), -+ PIN_CFG(USB2BXH, SCU410, GENMASK(7, 6), 2 << 6), -+ PIN_CFG(USB2BXHP, SCU410, GENMASK(7, 6), 2 << 6), -+ PIN_CFG(USB2BXH2A, SCU410, GENMASK(7, 6), 3 << 6), -+ PIN_CFG(USB2BXHP2A, SCU410, GENMASK(7, 6), 3 << 6), -+ PIN_CFG(USB2BD1, SCU410, GENMASK(7, 6), 1 << 6)); -+FUNCFG_DESCL(PORTA_U3_XHCI, PIN_CFG(USB3AXHD, SCU410, BIT_MASK(9), 1 << 9), -+ PIN_CFG(USB3AXHPD, SCU410, BIT_MASK(9), 0), -+ PIN_CFG(USB3AXH, SCU410, BIT_MASK(9), 1 << 9), -+ PIN_CFG(USB3AXHP, SCU410, BIT_MASK(9), 0), -+ PIN_CFG(USB3AXH2B, SCU410, BIT_MASK(9), 1 << 9), -+ PIN_CFG(USB3AXHP2B, SCU410, BIT_MASK(9), 0)); -+FUNCFG_DESCL(PORTA_U2_XHCI, PIN_CFG(USB2AXHD1, SCU410, BIT_MASK(9), 1 << 9), -+ PIN_CFG(USB2AXHPD1, SCU410, BIT_MASK(9), 0), -+ PIN_CFG(USB2AXH, SCU410, BIT_MASK(9), 1 << 9), -+ PIN_CFG(USB2AXHP, SCU410, BIT_MASK(9), 0), -+ PIN_CFG(USB2AXH2B, SCU410, BIT_MASK(9), 1 << 9), -+ PIN_CFG(USB2AXHP2B, SCU410, BIT_MASK(9), 0)); -+FUNCFG_DESCL(PORTB_U3_XHCI, PIN_CFG(USB3BXHD, SCU410, BIT_MASK(10), 1 << 10), -+ PIN_CFG(USB3BXHPD, SCU410, BIT_MASK(10), 0), -+ PIN_CFG(USB3BXH, SCU410, BIT_MASK(10), 1 << 10), -+ PIN_CFG(USB3BXHP, SCU410, BIT_MASK(10), 0), -+ PIN_CFG(USB3BXH2A, SCU410, BIT_MASK(10), 1 << 10), -+ PIN_CFG(USB3BXHP2A, SCU410, BIT_MASK(10), 0)); -+FUNCFG_DESCL(PORTB_U2_XHCI, PIN_CFG(USB2BXHD1, SCU410, BIT_MASK(10), 1 << 10), -+ PIN_CFG(USB2BXHPD1, SCU410, BIT_MASK(10), 0), -+ PIN_CFG(USB2BXH, SCU410, BIT_MASK(10), 1 << 10), -+ PIN_CFG(USB2BXHP, SCU410, BIT_MASK(10), 0), -+ PIN_CFG(USB2BXH2A, SCU410, BIT_MASK(10), 1 << 10), -+ PIN_CFG(USB2BXHP2A, SCU410, BIT_MASK(10), 0)); -+FUNCFG_DESCL(PORTA_MODE, PIN_CFG(USB2AHPD0, SCU410, GENMASK(25, 24), 0), -+ PIN_CFG(USB2AH, SCU410, GENMASK(25, 24), 2 << 24), -+ PIN_CFG(USB2AHP, SCU410, GENMASK(25, 24), 3 << 24), -+ PIN_CFG(USB2AD0, SCU410, GENMASK(25, 24), 1 << 24)); -+FUNCFG_DESCL(PORTB_MODE, PIN_CFG(USB2BHPD0, SCU410, GENMASK(29, 28), 0), -+ PIN_CFG(USB2BH, SCU410, GENMASK(29, 28), 2 << 28), -+ PIN_CFG(USB2BHP, SCU410, GENMASK(29, 28), 3 << 28), -+ PIN_CFG(USB2BD0, SCU410, GENMASK(29, 28), 1 << 28)); -+FUNCFG_DESCL(PORTA_U3_PHY); -+FUNCFG_DESCL(PORTA_U2_PHY); -+FUNCFG_DESCL(PORTB_U3_PHY); -+FUNCFG_DESCL(PORTB_U2_PHY); -+FUNCFG_DESCL(JTAG_PORT, PIN_CFG(PSP, SCU408, GENMASK(12, 5), 0x0 << 5), -+ PIN_CFG(SSP, SCU408, GENMASK(12, 5), 0x41 << 5), -+ PIN_CFG(TSP, SCU408, GENMASK(12, 5), 0x42 << 5), -+ PIN_CFG(DDR, SCU408, GENMASK(12, 5), 0x43 << 5), -+ PIN_CFG(USB3A, SCU408, GENMASK(12, 5), 0x44 << 5), -+ PIN_CFG(USB3B, SCU408, GENMASK(12, 5), 0x45 << 5), -+ PIN_CFG(PCIEA, SCU408, GENMASK(12, 5), 0x46 << 5), -+ PIN_CFG(PCIEB, SCU408, GENMASK(12, 5), 0x47 << 5), -+ PIN_CFG(JTAGM0, SCU408, GENMASK(12, 5), 0x8 << 5)); -+FUNCFG_DESCL(PCIERC0_PERST, PIN_CFG(PCIERC0PERST, SCU200, BIT_MASK(21), 1 << 21)); -+FUNCFG_DESCL(PCIERC1_PERST, PIN_CFG(PCIERC1PERST, SCU200, BIT_MASK(19), 1 << 19)); -+ -+static const struct aspeed_g7_pincfg pin_cfg[] = { -+ PINCFG_PIN(AC14), PINCFG_PIN(AE15), -+ PINCFG_PIN(AD14), PINCFG_PIN(AE14), -+ PINCFG_PIN(AF14), PINCFG_PIN(AB13), -+ PINCFG_PIN(AB14), PINCFG_PIN(AF15), -+ PINCFG_PIN(AF13), PINCFG_PIN(AC13), -+ PINCFG_PIN(AD13), PINCFG_PIN(AE13), -+ PINCFG_PIN(PORTA_U3), PINCFG_PIN(PORTA_U2), -+ PINCFG_PIN(PORTB_U3), PINCFG_PIN(PORTB_U2), -+ PINCFG_PIN(PORTA_U3_XHCI), PINCFG_PIN(PORTA_U2_XHCI), -+ PINCFG_PIN(PORTB_U3_XHCI), PINCFG_PIN(PORTB_U2_XHCI), -+ PINCFG_PIN(PORTA_MODE), PINCFG_PIN(PORTB_MODE), -+ PINCFG_PIN(PORTA_U3_PHY), PINCFG_PIN(PORTA_U2_PHY), -+ PINCFG_PIN(PORTB_U3_PHY), PINCFG_PIN(PORTB_U2_PHY), -+ PINCFG_PIN(JTAG_PORT), PINCFG_PIN(PCIERC0_PERST), -+ PINCFG_PIN(PCIERC1_PERST), -+}; -+ -+static const struct pinctrl_ops aspeed_g7_soc0_pinctrl_ops = { -+ .get_groups_count = aspeed_pinctrl_get_groups_count, -+ .get_group_name = aspeed_pinctrl_get_group_name, -+ .get_group_pins = aspeed_pinctrl_get_group_pins, -+ .pin_dbg_show = aspeed_pinctrl_pin_dbg_show, -+ .dt_node_to_map = pinconf_generic_dt_node_to_map_all, -+ .dt_free_map = pinctrl_utils_free_map, -+}; -+ -+static const struct pinmux_ops aspeed_g7_soc0_pinmux_ops = { -+ .get_functions_count = aspeed_pinmux_get_fn_count, -+ .get_function_name = aspeed_pinmux_get_fn_name, -+ .get_function_groups = aspeed_pinmux_get_fn_groups, -+ .set_mux = aspeed_g7_pinmux_set_mux, -+ .gpio_request_enable = aspeed_g7_gpio_request_enable, -+ .strict = true, -+}; -+ -+static const struct pinconf_ops aspeed_g7_soc0_pinconf_ops = { -+ .is_generic = true, -+ .pin_config_get = aspeed_pin_config_get, -+ .pin_config_set = aspeed_pin_config_set, -+ .pin_config_group_get = aspeed_pin_config_group_get, -+ .pin_config_group_set = aspeed_pin_config_group_set, -+}; -+ -+/* pinctrl_desc */ -+static struct pinctrl_desc aspeed_g7_soc0_pinctrl_desc = { -+ .name = "aspeed-g7-soc0-pinctrl", -+ .pins = aspeed_g7_soc0_pins, -+ .npins = ARRAY_SIZE(aspeed_g7_soc0_pins), -+ .pctlops = &aspeed_g7_soc0_pinctrl_ops, -+ .pmxops = &aspeed_g7_soc0_pinmux_ops, -+ .confops = &aspeed_g7_soc0_pinconf_ops, -+ .owner = THIS_MODULE, -+}; -+ -+static struct aspeed_pin_config aspeed_g7_configs[] = { -+ /* GPIO18A */ -+ { PIN_CONFIG_DRIVE_STRENGTH, { AC14, AC14 }, SCU480, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AE15, AE15 }, SCU484, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AD14, AD14 }, SCU488, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AE14, AE14 }, SCU48C, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AF14, AF14 }, SCU490, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AB13, AB13 }, SCU494, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AB14, AB14 }, SCU498, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AF15, AF15 }, SCU49C, GENMASK(3, 0) }, -+ /* GPIO18B */ -+ { PIN_CONFIG_DRIVE_STRENGTH, { AF13, AF13 }, SCU4A0, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AC13, AC13 }, SCU4A4, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AD13, AD13 }, SCU4A8, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AE13, AE13 }, SCU4AC, GENMASK(3, 0) }, -+}; -+ -+static const struct aspeed_pin_config_map aspeed_g7_pin_config_map[] = { -+ { PIN_CONFIG_DRIVE_STRENGTH, 0, 0, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, 1, 1, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, 2, 2, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, 3, 3, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, 4, 4, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, 5, 5, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, 6, 6, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, 7, 7, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, 8, 8, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, 9, 9, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, 10, 10, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, 11, 11, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, 12, 12, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, 13, 13, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, 14, 14, GENMASK(3, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, 15, 15, GENMASK(3, 0) }, -+ -+}; -+ -+static struct aspeed_pinctrl_data aspeed_g7_pinctrl_data = { -+ .pins = aspeed_g7_soc0_pins, -+ .npins = ARRAY_SIZE(aspeed_g7_soc0_pins), -+ .pinmux = { -+ .groups = aspeed_g7_soc0_pingroups, -+ .ngroups = ARRAY_SIZE(aspeed_g7_soc0_pingroups), -+ .functions = aspeed_g7_soc0_funcs, -+ .nfunctions = ARRAY_SIZE(aspeed_g7_soc0_funcs), -+ .configs_g7 = pin_cfg, -+ .nconfigs_g7 = ARRAY_SIZE(pin_cfg), -+ }, -+ .configs = aspeed_g7_configs, -+ .nconfigs = ARRAY_SIZE(aspeed_g7_configs), -+ .confmaps = aspeed_g7_pin_config_map, -+ .nconfmaps = ARRAY_SIZE(aspeed_g7_pin_config_map), -+}; -+ -+static int aspeed_g7_soc0_pinctrl_probe(struct platform_device *pdev) -+{ -+ return aspeed_pinctrl_probe(pdev, &aspeed_g7_soc0_pinctrl_desc, -+ &aspeed_g7_pinctrl_data); -+} -+ -+static const struct of_device_id aspeed_g7_soc0_pinctrl_match[] = { -+ { .compatible = "aspeed,ast2700-soc0-pinctrl" }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, aspeed_g7_soc0_pinctrl_match); -+ -+static struct platform_driver aspeed_g7_soc0_pinctrl_driver = { -+ .probe = aspeed_g7_soc0_pinctrl_probe, -+ .driver = { -+ .name = "aspeed-g7-soc0-pinctrl", -+ .of_match_table = aspeed_g7_soc0_pinctrl_match, -+ .suppress_bind_attrs = true, -+ }, -+}; -+ -+static int __init aspeed_g7_soc0_pinctrl_register(void) -+{ -+ return platform_driver_register(&aspeed_g7_soc0_pinctrl_driver); -+} -+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 2026-04-08 18:03:48.323705083 +0000 -@@ -0,0 +1,2533 @@ -+// SPDX-License-Identifier: GPL-2.0 -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "pinctrl-aspeed.h" -+ -+#define SCU3B0 0x3B0 /* USB Controller Register */ -+#define SCU3B4 0x3B4 /* USB Controller Lock Register */ -+#define SCU3B8 0x3B8 /* USB Controller Secure Register #1 */ -+#define SCU3BC 0x3BC /* USB Controller Secure Register #2 */ -+#define SCU3C0 0x3C0 /* USB Controller Secure Register #3 */ -+#define SCU400 0x400 /* Multi-function Pin Control #1 */ -+#define SCU404 0x404 /* Multi-function Pin Control #2 */ -+#define SCU408 0x408 /* Multi-function Pin Control #3 */ -+#define SCU40C 0x40C /* Multi-function Pin Control #4 */ -+#define SCU410 0x410 /* Multi-function Pin Control #5 */ -+#define SCU414 0x414 /* Multi-function Pin Control #6 */ -+#define SCU418 0x418 /* Multi-function Pin Control #7 */ -+#define SCU41C 0x41C /* Multi-function Pin Control #8 */ -+#define SCU420 0x420 /* Multi-function Pin Control #9 */ -+#define SCU424 0x424 /* Multi-function Pin Control #10 */ -+#define SCU428 0x428 /* Multi-function Pin Control #11 */ -+#define SCU42C 0x42C /* Multi-function Pin Control #12 */ -+#define SCU430 0x430 /* Multi-function Pin Control #13 */ -+#define SCU434 0x434 /* Multi-function Pin Control #14 */ -+#define SCU438 0x438 /* Multi-function Pin Control #15 */ -+#define SCU43C 0x43C /* Multi-function Pin Control #16 */ -+#define SCU440 0x440 /* Multi-function Pin Control #17 */ -+#define SCU444 0x444 /* Multi-function Pin Control #18 */ -+#define SCU448 0x448 /* Multi-function Pin Control #19 */ -+#define SCU44C 0x44C /* Multi-function Pin Control #20 */ -+#define SCU450 0x450 /* Multi-function Pin Control #21 */ -+#define SCU454 0x454 /* Multi-function Pin Control #22 */ -+#define SCU458 0x458 /* Multi-function Pin Control #23 */ -+#define SCU45C 0x45C /* Multi-function Pin Control #24 */ -+#define SCU460 0x460 /* Multi-function Pin Control #25 */ -+#define SCU464 0x464 /* Multi-function Pin Control #26 */ -+#define SCU468 0x468 /* Multi-function Pin Control #27 */ -+#define SCU46C 0x46C /* Multi-function Pin Control #28 */ -+#define SCU470 0x470 /* Multi-function Pin Control #29 */ -+#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 */ -+#define SCU4C8 0x4C8 /* Driving Strength #2 L-M */ -+#define SCU4CC 0x4CC /* Driving Strength #3 N-O */ -+#define SCU4D0 0x4D0 /* Driving Strength #4 P-Q */ -+#define SCU4D4 0x4D4 /* Driving Strength #5 R-S */ -+#define SCU4D8 0x4D8 /* Driving Strength #6 T-U */ -+#define SCU4DC 0x4DC /* Driving Strength #7 W */ -+ -+#define SCU908 0x908 /* PCIe RC PERST Pin Control */ -+ -+enum { -+ C16, -+ C14, -+ C11, -+ D9, -+ F14, -+ D10, -+ C12, -+ C13, -+ AC26, -+ AA25, -+ AB23, -+ U22, -+ V21, -+ N26, -+ P25, -+ N25, -+ V23, -+ W22, -+ AB26, -+ AD26, -+ P26, -+ AE26, -+ AF26, -+ AF25, -+ AE25, -+ AD25, -+ AF23, -+ AF20, -+ AF21, -+ AE21, -+ AE23, -+ AD22, -+ AF17, -+ AA16, -+ Y16, -+ V17, -+ J13, -+ AB16, -+ AC16, -+ AF16, -+ AA15, -+ AB15, -+ AC15, -+ AD15, -+ Y15, -+ AA14, -+ W16, -+ V16, -+ AB18, -+ AC18, -+ K13, -+ AA17, -+ AB17, -+ AD16, -+ AC17, -+ AD17, -+ AE16, -+ AE17, -+ AB24, -+ W26, -+ HOLE0, -+ HOLE1, -+ HOLE2, -+ HOLE3, -+ W25, -+ Y23, -+ Y24, -+ W21, -+ AA23, -+ AC22, -+ AB22, -+ Y21, -+ AE20, -+ AF19, -+ Y22, -+ AA20, -+ AA22, -+ AB20, -+ AF18, -+ AE19, -+ AD20, -+ AC20, -+ AA21, -+ AB21, -+ AC19, -+ AE18, -+ AD19, -+ AD18, -+ U25, -+ U26, -+ Y26, -+ AA24, -+ R25, -+ AA26, -+ R26, -+ Y25, -+ B16, -+ D14, -+ B15, -+ B14, -+ C17, -+ B13, -+ E14, -+ C15, -+ D24, -+ B23, -+ B22, -+ C23, -+ B18, -+ B21, -+ M15, -+ B19, -+ B26, -+ A25, -+ A24, -+ B24, -+ E26, -+ A21, -+ A19, -+ A18, -+ D26, -+ C26, -+ A23, -+ A22, -+ B25, -+ F26, -+ A26, -+ A14, -+ E10, -+ E13, -+ D12, -+ F10, -+ E11, -+ F11, -+ F13, -+ N15, -+ C20, -+ C19, -+ A8, -+ R14, -+ A7, -+ P14, -+ D20, -+ A6, -+ B6, -+ N14, -+ B7, -+ B8, -+ B9, -+ M14, -+ J11, -+ E7, -+ D19, -+ B11, -+ D15, -+ B12, -+ B10, -+ P13, -+ C18, -+ C6, -+ C7, -+ D7, -+ N13, -+ C8, -+ C9, -+ C10, -+ M16, -+ A15, -+ G11, -+ H7, -+ H8, -+ H9, -+ H10, -+ H11, -+ J9, -+ J10, -+ E9, -+ F9, -+ F8, -+ M13, -+ F7, -+ D8, -+ E8, -+ L12, -+ F12, -+ E12, -+ J12, -+ G7, -+ G8, -+ G9, -+ G10, -+ K12, -+ W17, -+ V18, -+ W18, -+ Y17, -+ AA18, -+ AA13, -+ Y18, -+ AA12, -+ W20, -+ V20, -+ Y11, -+ V14, -+ V19, -+ W14, -+ Y20, -+ AB19, -+ U21, -+ T24, -+ V24, -+ V22, -+ T23, -+ AC25, -+ AB25, -+ AC24, -+ SGMII0, -+ PCIERC2_PERST, -+ PORTC_MODE, // SCU3B0[1:0] -+ PORTD_MODE, // SCU3B0[3:2] -+}; -+ -+GROUP_DECL(ESPI0, B16, D14, B15, B14, C17, B13, E14, C15); -+GROUP_DECL(ESPI1, C16, C14, C11, D9, F14, D10, C12, C13); -+GROUP_DECL(LPC0, AF26, AF25, B16, D14, B15, B14, C17, B13, E14, C15); -+GROUP_DECL(LPC1, C16, C14, C11, D9, F14, D10, C12, C13, AE16, AE17); -+GROUP_DECL(SD, C16, C14, C11, D9, F14, D10, C12, C13); -+GROUP_DECL(VPI, C16, C14, C11, D9, F14, D10, C12, C13, AC26, AA25, AB23, U22, -+ V21, N26, P25, N25, V23, W22, AB26, AD26, P26, AE26, AF26, AF25, -+ AE25, AD25, AF23, AF20, AF21, AE21); -+GROUP_DECL(OSCCLK, C17); -+GROUP_DECL(TACH0, AC26); -+GROUP_DECL(TACH1, AA25); -+GROUP_DECL(TACH2, AB23); -+GROUP_DECL(TACH3, U22); -+GROUP_DECL(THRU0, AC26, AA25); -+GROUP_DECL(THRU1, AB23, U22); -+GROUP_DECL(TACH4, V21); -+GROUP_DECL(TACH5, N26); -+GROUP_DECL(TACH6, P25); -+GROUP_DECL(TACH7, N25); -+GROUP_DECL(NTCS5, V21); -+GROUP_DECL(NDCD5, N26); -+GROUP_DECL(NDSR5, P25); -+GROUP_DECL(NRI5, N25); -+GROUP_DECL(SALT12, AB26); -+GROUP_DECL(SALT13, AD26); -+GROUP_DECL(SALT14, P26); -+GROUP_DECL(SALT15, AE26); -+GROUP_DECL(NDTR5, V23); -+GROUP_DECL(NRTS5, W22); -+GROUP_DECL(NCTS6, AB26); -+GROUP_DECL(NDCD6, AD26); -+GROUP_DECL(NDSR6, P26); -+GROUP_DECL(NRI6, AE26); -+GROUP_DECL(NDTR6, AF26); -+GROUP_DECL(NRTS6, AF25); -+GROUP_DECL(TACH8, V23); -+GROUP_DECL(TACH9, W22); -+GROUP_DECL(TACH10, AB26); -+GROUP_DECL(TACH11, AD26); -+GROUP_DECL(TACH12, P26); -+GROUP_DECL(TACH13, AE26); -+GROUP_DECL(TACH14, AF26); -+GROUP_DECL(TACH15, AF25); -+GROUP_DECL(SPIM0, AE25, AD25, AF23, AF20, AF21, AE21, AE23); -+GROUP_DECL(PWM0, AE25); -+GROUP_DECL(PWM1, AD25); -+GROUP_DECL(PWM2, AF23); -+GROUP_DECL(PWM3, AF20); -+GROUP_DECL(PWM4, AF21); -+GROUP_DECL(PWM5, AE21); -+GROUP_DECL(PWM6, AE23); -+GROUP_DECL(PWM7, AD22); -+GROUP_DECL(SIOPBON0, AE25); -+GROUP_DECL(SIOPBIN0, AD25); -+GROUP_DECL(SIOSCIN0, AF23); -+GROUP_DECL(SIOS3N0, AF20); -+GROUP_DECL(SIOS5N0, AF21); -+GROUP_DECL(SIOPWREQN0, AE21); -+GROUP_DECL(SIOONCTRLN0, AE23); -+GROUP_DECL(SIOPWRGD0, AD22); -+GROUP_DECL(NCTS0, AF17); -+GROUP_DECL(NDCD0, AA16); -+GROUP_DECL(NDSR0, Y16); -+GROUP_DECL(NRI0, V17); -+GROUP_DECL(NDTR0, J13); -+GROUP_DECL(NRTS0, AB16); -+GROUP_DECL(TXD0, AC16); -+GROUP_DECL(RXD0, AF16); -+GROUP_DECL(NCTS1, AA15); -+GROUP_DECL(NDCD1, AB15); -+GROUP_DECL(NDSR1, AC15); -+GROUP_DECL(NRI1, AD15); -+GROUP_DECL(NDTR1, Y15); -+GROUP_DECL(NRTS1, AA14); -+GROUP_DECL(TXD1, W16); -+GROUP_DECL(RXD1, V16); -+GROUP_DECL(TXD2, AB18); -+GROUP_DECL(RXD2, AC18); -+GROUP_DECL(TXD3, K13); -+GROUP_DECL(RXD3, AA17); -+GROUP_DECL(NCTS5, V21); -+GROUP_DECL(TXD5, AB17); -+GROUP_DECL(RXD5, AD16); -+GROUP_DECL(TXD6, AC17); -+GROUP_DECL(RXD6, AD17); -+GROUP_DECL(TXD7, AE16); -+GROUP_DECL(RXD7, AE17); -+GROUP_DECL(TXD8, M15); -+GROUP_DECL(RXD8, B19); -+GROUP_DECL(TXD9, B26); -+GROUP_DECL(RXD9, A25); -+GROUP_DECL(TXD10, A24); -+GROUP_DECL(RXD10, B24); -+GROUP_DECL(TXD11, E26); -+GROUP_DECL(RXD11, A21); -+GROUP_DECL(SPIM1, K13, AA17, AB17, AD16, AC17, AD17, AE16, AE17); -+GROUP_DECL(WDTRST0N, K13); -+GROUP_DECL(WDTRST1N, AA17); -+GROUP_DECL(WDTRST2N, AB17); -+GROUP_DECL(WDTRST3N, AD16); -+GROUP_DECL(WDTRST4N, AC25); -+GROUP_DECL(WDTRST5N, AB25); -+GROUP_DECL(WDTRST6N, AC24); -+GROUP_DECL(WDTRST7N, AB24); -+GROUP_DECL(PWM8, K13); -+GROUP_DECL(PWM9, AA17); -+GROUP_DECL(PWM10, AB17); -+GROUP_DECL(PWM11, AD16); -+GROUP_DECL(PWM12, AC17); -+GROUP_DECL(PWM13, AD17); -+GROUP_DECL(PWM14, AE16); -+GROUP_DECL(PWM15, AE17); -+GROUP_DECL(SALT0, AC17); -+GROUP_DECL(SALT1, AD17); -+GROUP_DECL(SALT2, AC15); -+GROUP_DECL(SALT3, AD15); -+GROUP_DECL(FSI0, AD20, AC20); -+GROUP_DECL(FSI1, AA21, AB21); -+GROUP_DECL(FSI2, AC19, AE18); -+GROUP_DECL(FSI3, AD19, AD18); -+GROUP_DECL(SPIM2, W25, Y23, Y24, W21, AA23, AC22, AB22, Y21); -+GROUP_DECL(SALT4, W17); -+GROUP_DECL(SALT5, V18); -+GROUP_DECL(SALT6, W18); -+GROUP_DECL(SALT7, Y17); -+GROUP_DECL(SALT8, AA18); -+GROUP_DECL(SALT9, AA13); -+GROUP_DECL(SALT10, Y18); -+GROUP_DECL(SALT11, AA12); -+GROUP_DECL(ADC0, W17); -+GROUP_DECL(ADC1, V18); -+GROUP_DECL(ADC2, W18); -+GROUP_DECL(ADC3, Y17); -+GROUP_DECL(ADC4, AA18); -+GROUP_DECL(ADC5, AA13); -+GROUP_DECL(ADC6, Y18); -+GROUP_DECL(ADC7, AA12); -+GROUP_DECL(ADC8, W20); -+GROUP_DECL(ADC9, V20); -+GROUP_DECL(ADC10, Y11); -+GROUP_DECL(ADC11, V14); -+GROUP_DECL(ADC12, V19); -+GROUP_DECL(ADC13, W14); -+GROUP_DECL(ADC14, Y20); -+GROUP_DECL(ADC15, AB19); -+GROUP_DECL(AUXPWRGOOD0, W14); -+GROUP_DECL(AUXPWRGOOD1, Y20); -+GROUP_DECL(SGPM0, U21, T24, V22, T23); -+GROUP_DECL(SGPM1, AC25, AB25, AB24, W26); -+GROUP_DECL(I2C0, G11, H7); -+GROUP_DECL(I2C1, H8, H9); -+GROUP_DECL(I2C2, H10, H11); -+GROUP_DECL(I2C3, J9, J10); -+GROUP_DECL(I2C4, E9, F9); -+GROUP_DECL(I2C5, F8, M13); -+GROUP_DECL(I2C6, F7, D8); -+GROUP_DECL(I2C7, E8, L12); -+GROUP_DECL(I2C8, F12, E12); -+GROUP_DECL(I2C9, J12, G7); -+GROUP_DECL(I2C10, G8, G9); -+GROUP_DECL(I2C11, G10, K12); -+GROUP_DECL(I2C12, AC18, AA17); -+GROUP_DECL(I2C13, AB17, AD16); -+GROUP_DECL(I2C14, AC17, AD17); -+GROUP_DECL(I2C15, AE16, AE17); -+GROUP_DECL(DI2C0, C16, D9); -+GROUP_DECL(DI2C1, C14, F14); -+GROUP_DECL(DI2C2, D10, C12); -+GROUP_DECL(DI2C3, C11, C13); -+GROUP_DECL(DI2C8, U25, U26); -+GROUP_DECL(DI2C9, Y26, AA24); -+GROUP_DECL(DI2C10, R25, AA26); -+GROUP_DECL(DI2C11, R26, Y25); -+GROUP_DECL(DI2C12, W25, Y23); -+GROUP_DECL(DI2C13, Y24, W21); -+GROUP_DECL(DI2C14, AA23, AC22); -+GROUP_DECL(DI2C15, AB22, Y21); -+GROUP_DECL(LTPI_PS_I2C0, G11, H7); -+GROUP_DECL(LTPI_PS_I2C1, H8, H9); -+GROUP_DECL(LTPI_PS_I2C2, H10, H11); -+GROUP_DECL(LTPI_PS_I2C3, J9, J10); -+GROUP_DECL(SIOPBON1, AF17); -+GROUP_DECL(SIOPBIN1, AA16); -+GROUP_DECL(SIOSCIN1, Y16); -+GROUP_DECL(SIOS3N1, V17); -+GROUP_DECL(SIOS5N1, J13); -+GROUP_DECL(SIOPWREQN1, AB16); -+GROUP_DECL(SIOONCTRLN1, AA15); -+GROUP_DECL(SIOPWRGD1, AB15); -+GROUP_DECL(HVI3C12, W25, Y23); -+GROUP_DECL(HVI3C13, Y24, W21); -+GROUP_DECL(HVI3C14, AA23, AC22); -+GROUP_DECL(HVI3C15, AB22, Y21); -+GROUP_DECL(I3C4, AE20, AF19); -+GROUP_DECL(I3C5, Y22, AA20); -+GROUP_DECL(I3C6, AA22, AB20); -+GROUP_DECL(I3C7, AF18, AE19); -+GROUP_DECL(I3C8, AD20, AC20); -+GROUP_DECL(I3C9, AA21, AB21); -+GROUP_DECL(I3C10, AC19, AE18); -+GROUP_DECL(I3C11, AD19, AD18); -+GROUP_DECL(HVI3C0, U25, U26); -+GROUP_DECL(HVI3C1, Y26, AA24); -+GROUP_DECL(HVI3C2, R25, AA26); -+GROUP_DECL(HVI3C3, R26, Y25); -+GROUP_DECL(LTPI, U25, U26, Y26, AA24); -+GROUP_DECL(SPI0, D24, B23, B22); -+GROUP_DECL(QSPI0, C23, B18); -+GROUP_DECL(SPI0CS1, B21); -+GROUP_DECL(SPI0ABR, M15); -+GROUP_DECL(SPI0WPN, B19); -+GROUP_DECL(SPI1, B26, A25, A24); -+GROUP_DECL(QSPI1, B24, E26); -+GROUP_DECL(SPI1CS1, A21); -+GROUP_DECL(SPI1ABR, A19); -+GROUP_DECL(SPI1WPN, A18); -+GROUP_DECL(SPI2, D26, C26, A23, A22); -+GROUP_DECL(QSPI2, B25, F26); -+GROUP_DECL(SPI2CS1, A26); -+GROUP_DECL(THRU2, A19, A18); -+GROUP_DECL(THRU3, B25, F26); -+GROUP_DECL(JTAGM1, D12, F10, E11, F11, F13); -+GROUP_DECL(MDIO0, B9, M14); -+GROUP_DECL(MDIO1, C9, C10); -+GROUP_DECL(MDIO2, E10, E13); -+GROUP_DECL(FWQSPI, M16, A15); -+GROUP_DECL(FWSPIABR, A14); -+GROUP_DECL(FWSPIWPN, N15); -+GROUP_DECL(RGMII0, C20, C19, A8, R14, A7, P14, D20, A6, B6, N14, B7, B8); -+GROUP_DECL(RGMII1, D19, B11, D15, B12, B10, P13, C18, C6, C7, D7, N13, C8); -+GROUP_DECL(RMII0, C20, A8, R14, A7, P14, A6, B6, N14); -+GROUP_DECL(RMII0RCLKO, D20); -+GROUP_DECL(RMII1, D19, D15, B12, B10, P13, C6, C7, D7); -+GROUP_DECL(RMII1RCLKO, C18); -+GROUP_DECL(VGA, J11, E7); -+GROUP_DECL(DSGPM0, D19, B10, C7, D7); -+GROUP_DECL(SGPS, B11, C18, N13, C8); -+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(USBUART, G10, K12); -+GROUP_DECL(HBLED, V24); -+GROUP_DECL(MACLINK0, U21); -+GROUP_DECL(MACLINK1, AC24); -+GROUP_DECL(MACLINK2, T24); -+GROUP_DECL(NCTS2, U21); -+GROUP_DECL(NDCD2, T24); -+GROUP_DECL(NDSR2, V22); -+GROUP_DECL(NRI2, T23); -+GROUP_DECL(NDTR2, AC25); -+GROUP_DECL(NRTS2, AB25); -+GROUP_DECL(SMON0, U21, T24, V22, T23); -+GROUP_DECL(SMON1, AB24, W26, AC25, AB25); -+GROUP_DECL(SGMII, SGMII0); -+//PCIE RC PERST -+GROUP_DECL(PE2SGRSTN, PCIERC2_PERST, E10); -+GROUP_DECL(USB2CUD, PORTC_MODE); -+GROUP_DECL(USB2CD, PORTC_MODE); -+GROUP_DECL(USB2CH, PORTC_MODE); -+GROUP_DECL(USB2CU, PORTC_MODE); -+GROUP_DECL(USB2DD, PORTD_MODE); -+GROUP_DECL(USB2DH, PORTD_MODE); -+ -+static struct aspeed_pin_group aspeed_g7_soc1_pingroups[] = { -+ ASPEED_PINCTRL_GROUP(ESPI0), -+ ASPEED_PINCTRL_GROUP(ESPI1), -+ ASPEED_PINCTRL_GROUP(LPC0), -+ ASPEED_PINCTRL_GROUP(LPC1), -+ ASPEED_PINCTRL_GROUP(SD), -+ ASPEED_PINCTRL_GROUP(VPI), -+ ASPEED_PINCTRL_GROUP(OSCCLK), -+ ASPEED_PINCTRL_GROUP(TACH0), -+ ASPEED_PINCTRL_GROUP(TACH1), -+ ASPEED_PINCTRL_GROUP(TACH2), -+ ASPEED_PINCTRL_GROUP(TACH3), -+ ASPEED_PINCTRL_GROUP(THRU0), -+ ASPEED_PINCTRL_GROUP(THRU1), -+ ASPEED_PINCTRL_GROUP(TACH4), -+ ASPEED_PINCTRL_GROUP(TACH5), -+ ASPEED_PINCTRL_GROUP(TACH6), -+ ASPEED_PINCTRL_GROUP(TACH7), -+ ASPEED_PINCTRL_GROUP(NTCS5), -+ ASPEED_PINCTRL_GROUP(NDCD5), -+ ASPEED_PINCTRL_GROUP(NDSR5), -+ ASPEED_PINCTRL_GROUP(NRI5), -+ ASPEED_PINCTRL_GROUP(SALT12), -+ ASPEED_PINCTRL_GROUP(SALT13), -+ ASPEED_PINCTRL_GROUP(SALT14), -+ ASPEED_PINCTRL_GROUP(SALT15), -+ ASPEED_PINCTRL_GROUP(NDTR5), -+ ASPEED_PINCTRL_GROUP(NRTS5), -+ ASPEED_PINCTRL_GROUP(NCTS6), -+ ASPEED_PINCTRL_GROUP(NDCD6), -+ ASPEED_PINCTRL_GROUP(NDSR6), -+ ASPEED_PINCTRL_GROUP(NRI6), -+ ASPEED_PINCTRL_GROUP(NDTR6), -+ ASPEED_PINCTRL_GROUP(NRTS6), -+ ASPEED_PINCTRL_GROUP(TACH8), -+ ASPEED_PINCTRL_GROUP(TACH9), -+ ASPEED_PINCTRL_GROUP(TACH10), -+ ASPEED_PINCTRL_GROUP(TACH11), -+ ASPEED_PINCTRL_GROUP(TACH12), -+ ASPEED_PINCTRL_GROUP(TACH13), -+ ASPEED_PINCTRL_GROUP(TACH14), -+ ASPEED_PINCTRL_GROUP(TACH15), -+ ASPEED_PINCTRL_GROUP(SPIM0), -+ ASPEED_PINCTRL_GROUP(PWM0), -+ ASPEED_PINCTRL_GROUP(PWM1), -+ ASPEED_PINCTRL_GROUP(PWM2), -+ ASPEED_PINCTRL_GROUP(PWM3), -+ ASPEED_PINCTRL_GROUP(PWM4), -+ ASPEED_PINCTRL_GROUP(PWM5), -+ ASPEED_PINCTRL_GROUP(PWM6), -+ ASPEED_PINCTRL_GROUP(PWM7), -+ ASPEED_PINCTRL_GROUP(SIOPBON0), -+ ASPEED_PINCTRL_GROUP(SIOPBIN0), -+ ASPEED_PINCTRL_GROUP(SIOSCIN0), -+ ASPEED_PINCTRL_GROUP(SIOS3N0), -+ ASPEED_PINCTRL_GROUP(SIOS5N0), -+ ASPEED_PINCTRL_GROUP(SIOPWREQN0), -+ ASPEED_PINCTRL_GROUP(SIOONCTRLN0), -+ ASPEED_PINCTRL_GROUP(SIOPWRGD0), -+ ASPEED_PINCTRL_GROUP(NCTS0), -+ ASPEED_PINCTRL_GROUP(NDCD0), -+ ASPEED_PINCTRL_GROUP(NDSR0), -+ ASPEED_PINCTRL_GROUP(NRI0), -+ ASPEED_PINCTRL_GROUP(NDTR0), -+ ASPEED_PINCTRL_GROUP(NRTS0), -+ ASPEED_PINCTRL_GROUP(TXD0), -+ ASPEED_PINCTRL_GROUP(RXD0), -+ ASPEED_PINCTRL_GROUP(NCTS1), -+ ASPEED_PINCTRL_GROUP(NDCD1), -+ ASPEED_PINCTRL_GROUP(NDSR1), -+ ASPEED_PINCTRL_GROUP(NRI1), -+ ASPEED_PINCTRL_GROUP(NDTR1), -+ ASPEED_PINCTRL_GROUP(NRTS1), -+ ASPEED_PINCTRL_GROUP(TXD1), -+ ASPEED_PINCTRL_GROUP(RXD1), -+ ASPEED_PINCTRL_GROUP(TXD2), -+ ASPEED_PINCTRL_GROUP(RXD2), -+ ASPEED_PINCTRL_GROUP(TXD3), -+ ASPEED_PINCTRL_GROUP(RXD3), -+ ASPEED_PINCTRL_GROUP(NCTS5), -+ ASPEED_PINCTRL_GROUP(NDCD5), -+ ASPEED_PINCTRL_GROUP(NDSR5), -+ ASPEED_PINCTRL_GROUP(NRI5), -+ ASPEED_PINCTRL_GROUP(NDTR5), -+ ASPEED_PINCTRL_GROUP(NRTS5), -+ ASPEED_PINCTRL_GROUP(TXD5), -+ ASPEED_PINCTRL_GROUP(RXD5), -+ ASPEED_PINCTRL_GROUP(NCTS6), -+ ASPEED_PINCTRL_GROUP(NDCD6), -+ ASPEED_PINCTRL_GROUP(NDSR6), -+ ASPEED_PINCTRL_GROUP(NRI6), -+ ASPEED_PINCTRL_GROUP(NDTR6), -+ ASPEED_PINCTRL_GROUP(NRTS6), -+ ASPEED_PINCTRL_GROUP(TXD6), -+ ASPEED_PINCTRL_GROUP(RXD6), -+ ASPEED_PINCTRL_GROUP(TXD6), -+ ASPEED_PINCTRL_GROUP(RXD6), -+ ASPEED_PINCTRL_GROUP(TXD7), -+ ASPEED_PINCTRL_GROUP(RXD7), -+ ASPEED_PINCTRL_GROUP(TXD8), -+ ASPEED_PINCTRL_GROUP(RXD8), -+ ASPEED_PINCTRL_GROUP(TXD9), -+ ASPEED_PINCTRL_GROUP(RXD9), -+ ASPEED_PINCTRL_GROUP(TXD10), -+ ASPEED_PINCTRL_GROUP(RXD10), -+ ASPEED_PINCTRL_GROUP(TXD11), -+ ASPEED_PINCTRL_GROUP(RXD11), -+ ASPEED_PINCTRL_GROUP(SPIM1), -+ ASPEED_PINCTRL_GROUP(WDTRST0N), -+ ASPEED_PINCTRL_GROUP(WDTRST1N), -+ ASPEED_PINCTRL_GROUP(WDTRST2N), -+ ASPEED_PINCTRL_GROUP(WDTRST3N), -+ ASPEED_PINCTRL_GROUP(WDTRST4N), -+ ASPEED_PINCTRL_GROUP(WDTRST5N), -+ ASPEED_PINCTRL_GROUP(WDTRST6N), -+ ASPEED_PINCTRL_GROUP(WDTRST7N), -+ ASPEED_PINCTRL_GROUP(PWM8), -+ ASPEED_PINCTRL_GROUP(PWM9), -+ ASPEED_PINCTRL_GROUP(PWM10), -+ ASPEED_PINCTRL_GROUP(PWM11), -+ ASPEED_PINCTRL_GROUP(PWM12), -+ ASPEED_PINCTRL_GROUP(PWM13), -+ ASPEED_PINCTRL_GROUP(PWM14), -+ ASPEED_PINCTRL_GROUP(PWM15), -+ ASPEED_PINCTRL_GROUP(SALT0), -+ ASPEED_PINCTRL_GROUP(SALT1), -+ ASPEED_PINCTRL_GROUP(SALT2), -+ ASPEED_PINCTRL_GROUP(SALT3), -+ ASPEED_PINCTRL_GROUP(FSI0), -+ ASPEED_PINCTRL_GROUP(FSI1), -+ ASPEED_PINCTRL_GROUP(FSI2), -+ ASPEED_PINCTRL_GROUP(FSI3), -+ ASPEED_PINCTRL_GROUP(SPIM2), -+ ASPEED_PINCTRL_GROUP(SALT4), -+ ASPEED_PINCTRL_GROUP(SALT5), -+ ASPEED_PINCTRL_GROUP(SALT6), -+ ASPEED_PINCTRL_GROUP(SALT7), -+ ASPEED_PINCTRL_GROUP(SALT8), -+ ASPEED_PINCTRL_GROUP(SALT9), -+ ASPEED_PINCTRL_GROUP(SALT10), -+ ASPEED_PINCTRL_GROUP(SALT11), -+ ASPEED_PINCTRL_GROUP(ADC0), -+ ASPEED_PINCTRL_GROUP(ADC1), -+ ASPEED_PINCTRL_GROUP(ADC2), -+ ASPEED_PINCTRL_GROUP(ADC3), -+ ASPEED_PINCTRL_GROUP(ADC4), -+ ASPEED_PINCTRL_GROUP(ADC5), -+ ASPEED_PINCTRL_GROUP(ADC6), -+ ASPEED_PINCTRL_GROUP(ADC7), -+ ASPEED_PINCTRL_GROUP(ADC8), -+ ASPEED_PINCTRL_GROUP(ADC9), -+ ASPEED_PINCTRL_GROUP(ADC10), -+ ASPEED_PINCTRL_GROUP(ADC11), -+ ASPEED_PINCTRL_GROUP(ADC12), -+ ASPEED_PINCTRL_GROUP(ADC13), -+ ASPEED_PINCTRL_GROUP(ADC14), -+ ASPEED_PINCTRL_GROUP(ADC15), -+ ASPEED_PINCTRL_GROUP(AUXPWRGOOD0), -+ ASPEED_PINCTRL_GROUP(AUXPWRGOOD1), -+ ASPEED_PINCTRL_GROUP(SGPM0), -+ ASPEED_PINCTRL_GROUP(SGPM1), -+ ASPEED_PINCTRL_GROUP(I2C0), -+ ASPEED_PINCTRL_GROUP(I2C1), -+ ASPEED_PINCTRL_GROUP(I2C2), -+ ASPEED_PINCTRL_GROUP(I2C3), -+ ASPEED_PINCTRL_GROUP(I2C4), -+ ASPEED_PINCTRL_GROUP(I2C5), -+ ASPEED_PINCTRL_GROUP(I2C6), -+ ASPEED_PINCTRL_GROUP(I2C7), -+ ASPEED_PINCTRL_GROUP(I2C8), -+ ASPEED_PINCTRL_GROUP(I2C9), -+ ASPEED_PINCTRL_GROUP(I2C10), -+ ASPEED_PINCTRL_GROUP(I2C11), -+ ASPEED_PINCTRL_GROUP(I2C12), -+ ASPEED_PINCTRL_GROUP(I2C13), -+ ASPEED_PINCTRL_GROUP(I2C14), -+ ASPEED_PINCTRL_GROUP(I2C15), -+ ASPEED_PINCTRL_GROUP(LTPI_PS_I2C0), -+ ASPEED_PINCTRL_GROUP(LTPI_PS_I2C1), -+ ASPEED_PINCTRL_GROUP(LTPI_PS_I2C2), -+ ASPEED_PINCTRL_GROUP(LTPI_PS_I2C3), -+ ASPEED_PINCTRL_GROUP(DI2C0), -+ ASPEED_PINCTRL_GROUP(DI2C1), -+ ASPEED_PINCTRL_GROUP(DI2C2), -+ ASPEED_PINCTRL_GROUP(DI2C3), -+ ASPEED_PINCTRL_GROUP(DI2C8), -+ ASPEED_PINCTRL_GROUP(DI2C9), -+ ASPEED_PINCTRL_GROUP(DI2C10), -+ ASPEED_PINCTRL_GROUP(DI2C11), -+ ASPEED_PINCTRL_GROUP(DI2C12), -+ ASPEED_PINCTRL_GROUP(DI2C13), -+ ASPEED_PINCTRL_GROUP(DI2C14), -+ ASPEED_PINCTRL_GROUP(DI2C15), -+ ASPEED_PINCTRL_GROUP(SIOPBON1), -+ ASPEED_PINCTRL_GROUP(SIOPBIN1), -+ ASPEED_PINCTRL_GROUP(SIOSCIN1), -+ ASPEED_PINCTRL_GROUP(SIOS3N1), -+ ASPEED_PINCTRL_GROUP(SIOS5N1), -+ ASPEED_PINCTRL_GROUP(SIOPWREQN1), -+ ASPEED_PINCTRL_GROUP(SIOONCTRLN1), -+ ASPEED_PINCTRL_GROUP(SIOPWRGD1), -+ ASPEED_PINCTRL_GROUP(HVI3C12), -+ ASPEED_PINCTRL_GROUP(HVI3C13), -+ ASPEED_PINCTRL_GROUP(HVI3C14), -+ ASPEED_PINCTRL_GROUP(HVI3C15), -+ ASPEED_PINCTRL_GROUP(I3C4), -+ ASPEED_PINCTRL_GROUP(I3C5), -+ ASPEED_PINCTRL_GROUP(I3C6), -+ ASPEED_PINCTRL_GROUP(I3C7), -+ ASPEED_PINCTRL_GROUP(I3C8), -+ ASPEED_PINCTRL_GROUP(I3C9), -+ ASPEED_PINCTRL_GROUP(I3C10), -+ ASPEED_PINCTRL_GROUP(I3C11), -+ ASPEED_PINCTRL_GROUP(HVI3C0), -+ ASPEED_PINCTRL_GROUP(HVI3C1), -+ ASPEED_PINCTRL_GROUP(HVI3C2), -+ ASPEED_PINCTRL_GROUP(HVI3C3), -+ ASPEED_PINCTRL_GROUP(LTPI), -+ ASPEED_PINCTRL_GROUP(SPI0), -+ ASPEED_PINCTRL_GROUP(QSPI0), -+ ASPEED_PINCTRL_GROUP(SPI0CS1), -+ ASPEED_PINCTRL_GROUP(SPI0ABR), -+ ASPEED_PINCTRL_GROUP(SPI0WPN), -+ ASPEED_PINCTRL_GROUP(SPI1), -+ ASPEED_PINCTRL_GROUP(QSPI1), -+ ASPEED_PINCTRL_GROUP(SPI1CS1), -+ ASPEED_PINCTRL_GROUP(SPI1ABR), -+ ASPEED_PINCTRL_GROUP(SPI1WPN), -+ ASPEED_PINCTRL_GROUP(SPI2), -+ ASPEED_PINCTRL_GROUP(QSPI2), -+ ASPEED_PINCTRL_GROUP(SPI2CS1), -+ ASPEED_PINCTRL_GROUP(THRU2), -+ ASPEED_PINCTRL_GROUP(THRU3), -+ ASPEED_PINCTRL_GROUP(JTAGM1), -+ ASPEED_PINCTRL_GROUP(MDIO0), -+ ASPEED_PINCTRL_GROUP(MDIO1), -+ ASPEED_PINCTRL_GROUP(MDIO2), -+ ASPEED_PINCTRL_GROUP(FWQSPI), -+ ASPEED_PINCTRL_GROUP(FWSPIABR), -+ ASPEED_PINCTRL_GROUP(FWSPIWPN), -+ ASPEED_PINCTRL_GROUP(RGMII0), -+ ASPEED_PINCTRL_GROUP(RGMII1), -+ ASPEED_PINCTRL_GROUP(RMII0), -+ ASPEED_PINCTRL_GROUP(RMII0RCLKO), -+ ASPEED_PINCTRL_GROUP(RMII1), -+ ASPEED_PINCTRL_GROUP(RMII1RCLKO), -+ ASPEED_PINCTRL_GROUP(VGA), -+ ASPEED_PINCTRL_GROUP(DSGPM0), -+ ASPEED_PINCTRL_GROUP(SGPS), -+ ASPEED_PINCTRL_GROUP(I2CF0), -+ ASPEED_PINCTRL_GROUP(I2CF1), -+ ASPEED_PINCTRL_GROUP(I2CF2), -+ ASPEED_PINCTRL_GROUP(CANBUS), -+ ASPEED_PINCTRL_GROUP(USBUART), -+ ASPEED_PINCTRL_GROUP(HBLED), -+ ASPEED_PINCTRL_GROUP(MACLINK0), -+ ASPEED_PINCTRL_GROUP(MACLINK1), -+ ASPEED_PINCTRL_GROUP(MACLINK2), -+ ASPEED_PINCTRL_GROUP(NCTS2), -+ ASPEED_PINCTRL_GROUP(NDCD2), -+ ASPEED_PINCTRL_GROUP(NDSR2), -+ ASPEED_PINCTRL_GROUP(NRI2), -+ ASPEED_PINCTRL_GROUP(NDTR2), -+ ASPEED_PINCTRL_GROUP(NRTS2), -+ ASPEED_PINCTRL_GROUP(SMON0), -+ ASPEED_PINCTRL_GROUP(SMON1), -+ ASPEED_PINCTRL_GROUP(SGMII), -+ ASPEED_PINCTRL_GROUP(PE2SGRSTN), -+ ASPEED_PINCTRL_GROUP(USB2CUD), -+ ASPEED_PINCTRL_GROUP(USB2CD), -+ ASPEED_PINCTRL_GROUP(USB2CH), -+ ASPEED_PINCTRL_GROUP(USB2CU), -+ ASPEED_PINCTRL_GROUP(USB2DD), -+ ASPEED_PINCTRL_GROUP(USB2DH), -+}; -+ -+FUNC_DECL_(ESPI0, "ESPI0"); -+FUNC_DECL_(ESPI1, "ESPI1"); -+FUNC_DECL_(LPC0, "LPC0"); -+FUNC_DECL_(LPC1, "LPC1"); -+FUNC_DECL_(VPI, "VPI"); -+FUNC_DECL_(SD, "SD"); -+FUNC_DECL_(OSCCLK, "OSCCLK"); -+FUNC_DECL_(TACH0, "TACH0"); -+FUNC_DECL_(TACH1, "TACH1"); -+FUNC_DECL_(TACH2, "TACH2"); -+FUNC_DECL_(TACH3, "TACH3"); -+FUNC_DECL_(TACH4, "TACH4"); -+FUNC_DECL_(TACH5, "TACH5"); -+FUNC_DECL_(TACH6, "TACH6"); -+FUNC_DECL_(TACH7, "TACH7"); -+FUNC_DECL_(THRU0, "THRU0"); -+FUNC_DECL_(THRU1, "THRU1"); -+FUNC_DECL_(NTCS5, "NTCS5"); -+FUNC_DECL_(NDSR5, "NDSR5"); -+FUNC_DECL_(NRI5, "NRI5"); -+FUNC_DECL_(TACH8, "TACH8"); -+FUNC_DECL_(TACH9, "TACH9"); -+FUNC_DECL_(TACH10, "TACH10"); -+FUNC_DECL_(TACH11, "TACH11"); -+FUNC_DECL_(TACH12, "TACH12"); -+FUNC_DECL_(TACH13, "TACH13"); -+FUNC_DECL_(TACH14, "TACH14"); -+FUNC_DECL_(TACH15, "TACH15"); -+FUNC_DECL_(SALT12, "SALT12"); -+FUNC_DECL_(SALT13, "SALT13"); -+FUNC_DECL_(SALT14, "SALT14"); -+FUNC_DECL_(SALT15, "SALT15"); -+FUNC_DECL_(SPIM0, "SPIM0"); -+FUNC_DECL_(PWM0, "PWM0"); -+FUNC_DECL_(PWM1, "PWM1"); -+FUNC_DECL_(PWM2, "PWM2"); -+FUNC_DECL_(PWM3, "PWM3"); -+FUNC_DECL_(PWM4, "PWM4"); -+FUNC_DECL_(PWM5, "PWM5"); -+FUNC_DECL_(PWM6, "PWM6"); -+FUNC_DECL_(PWM7, "PWM7"); -+FUNC_DECL_(SIOPBON0, "SIOPBON0"); -+FUNC_DECL_(SIOPBIN0, "SIOPBIN0"); -+FUNC_DECL_(SIOSCIN0, "SIOSCIN0"); -+FUNC_DECL_(SIOS3N0, "SIOS3N0"); -+FUNC_DECL_(SIOS5N0, "SIOS5N0"); -+FUNC_DECL_(SIOPWREQN0, "SIOPWREQN0"); -+FUNC_DECL_(SIOONCTRLN0, "SIOONCTRLN0"); -+FUNC_DECL_(SIOPWRGD0, "SIOPWRGD0"); -+FUNC_DECL_(UART0, "NCTS0", "NDCD0", "NDSR0", "NRI0", "NDTR0", "NRTS0", "TXD0", "RXD0"); -+FUNC_DECL_(UART1, "NCTS1", "NDCD1", "NDSR1", "NRI1", "NDTR1", "NRTS1", "TXD1", "RXD1"); -+FUNC_DECL_(UART2, "TXD2", "RXD2"); -+FUNC_DECL_(UART3, "TXD3", "RXD3"); -+FUNC_DECL_(UART5, "NCTS5", "NDCD5", "NDSR5", "NRI5", "NDTR5", "NRTS5", "TXD5", "RXD5"); -+FUNC_DECL_(UART6, "NCTS6", "NDCD6", "NDSR6", "NRI6", "NDTR6", "NRTS6", "TXD6", "RXD6"); -+FUNC_DECL_(UART7, "TXD7", "RXD7"); -+FUNC_DECL_(UART8, "TXD8", "RXD8"); -+FUNC_DECL_(UART9, "TXD9", "RXD9"); -+FUNC_DECL_(UART10, "TXD10", "RXD10"); -+FUNC_DECL_(UART11, "TXD11", "RXD11"); -+FUNC_DECL_(SPIM1, "SPIM1"); -+FUNC_DECL_(SPIM2, "SPIM2"); -+FUNC_DECL_(PWM8, "PWM8"); -+FUNC_DECL_(PWM9, "PWM9"); -+FUNC_DECL_(PWM10, "PWM10"); -+FUNC_DECL_(PWM11, "PWM11"); -+FUNC_DECL_(PWM12, "PWM12"); -+FUNC_DECL_(PWM13, "PWM13"); -+FUNC_DECL_(PWM14, "PWM14"); -+FUNC_DECL_(PWM15, "PWM15"); -+FUNC_DECL_(WDTRST0N, "WDTRST0N"); -+FUNC_DECL_(WDTRST1N, "WDTRST1N"); -+FUNC_DECL_(WDTRST2N, "WDTRST2N"); -+FUNC_DECL_(WDTRST3N, "WDTRST3N"); -+FUNC_DECL_(WDTRST4N, "WDTRST4N"); -+FUNC_DECL_(WDTRST5N, "WDTRST5N"); -+FUNC_DECL_(WDTRST6N, "WDTRST6N"); -+FUNC_DECL_(WDTRST7N, "WDTRST7N"); -+FUNC_DECL_(FSI0, "FSI0"); -+FUNC_DECL_(FSI1, "FSI1"); -+FUNC_DECL_(FSI2, "FSI2"); -+FUNC_DECL_(FSI3, "FSI3"); -+FUNC_DECL_(SALT0, "SALT0"); -+FUNC_DECL_(SALT1, "SALT1"); -+FUNC_DECL_(SALT2, "SALT2"); -+FUNC_DECL_(SALT3, "SALT3"); -+FUNC_DECL_(SALT4, "SALT4"); -+FUNC_DECL_(SALT5, "SALT5"); -+FUNC_DECL_(SALT6, "SALT6"); -+FUNC_DECL_(SALT7, "SALT7"); -+FUNC_DECL_(SALT8, "SALT8"); -+FUNC_DECL_(SALT9, "SALT9"); -+FUNC_DECL_(SALT10, "SALT10"); -+FUNC_DECL_(SALT11, "SALT11"); -+FUNC_DECL_(ADC0, "ADC0"); -+FUNC_DECL_(ADC1, "ADC1"); -+FUNC_DECL_(ADC2, "ADC2"); -+FUNC_DECL_(ADC3, "ADC3"); -+FUNC_DECL_(ADC4, "ADC4"); -+FUNC_DECL_(ADC5, "ADC5"); -+FUNC_DECL_(ADC6, "ADC6"); -+FUNC_DECL_(ADC7, "ADC7"); -+FUNC_DECL_(ADC8, "ADC8"); -+FUNC_DECL_(ADC9, "ADC9"); -+FUNC_DECL_(ADC10, "ADC10"); -+FUNC_DECL_(ADC11, "ADC11"); -+FUNC_DECL_(ADC12, "ADC12"); -+FUNC_DECL_(ADC13, "ADC13"); -+FUNC_DECL_(ADC14, "ADC14"); -+FUNC_DECL_(ADC15, "ADC15"); -+FUNC_DECL_(AUXPWRGOOD0, "AUXPWRGOOD0"); -+FUNC_DECL_(AUXPWRGOOD1, "AUXPWRGOOD1"); -+FUNC_DECL_(SGPM0, "SGPM0", "DSGPM0"); -+FUNC_DECL_(SGPM1, "SGPM1"); -+FUNC_DECL_(LTPI_PS_I2C0, "LTPI_PS_I2C0"); -+FUNC_DECL_(LTPI_PS_I2C1, "LTPI_PS_I2C1"); -+FUNC_DECL_(LTPI_PS_I2C2, "LTPI_PS_I2C2"); -+FUNC_DECL_(LTPI_PS_I2C3, "LTPI_PS_I2C3"); -+FUNC_DECL_(I2C0, "I2C0", "DI2C0"); -+FUNC_DECL_(I2C1, "I2C1", "DI2C1"); -+FUNC_DECL_(I2C2, "I2C2", "DI2C2"); -+FUNC_DECL_(I2C3, "I2C3", "DI2C3"); -+FUNC_DECL_(I2C4, "I2C4"); -+FUNC_DECL_(I2C5, "I2C5"); -+FUNC_DECL_(I2C6, "I2C6"); -+FUNC_DECL_(I2C7, "I2C7"); -+FUNC_DECL_(I2C8, "I2C8", "DI2C8"); -+FUNC_DECL_(I2C9, "I2C9", "DI2C9"); -+FUNC_DECL_(I2C10, "I2C10", "DI2C10"); -+FUNC_DECL_(I2C11, "I2C11", "DI2C11"); -+FUNC_DECL_(I2C12, "I2C12", "DI2C12"); -+FUNC_DECL_(I2C13, "I2C13", "DI2C13"); -+FUNC_DECL_(I2C14, "I2C14", "DI2C14"); -+FUNC_DECL_(I2C15, "I2C15", "DI2C15"); -+FUNC_DECL_(SIOPBON1, "SIOPBON1"); -+FUNC_DECL_(SIOPBIN1, "SIOPBIN1"); -+FUNC_DECL_(SIOSCIN1, "SIOSCIN1"); -+FUNC_DECL_(SIOS3N1, "SIOS3N1"); -+FUNC_DECL_(SIOS5N1, "SIOS5N1"); -+FUNC_DECL_(SIOPWREQN1, "SIOPWREQN1"); -+FUNC_DECL_(SIOONCTRLN1, "SIOONCTRLN1"); -+FUNC_DECL_(SIOPWRGD1, "SIOPWRGD1"); -+FUNC_DECL_(I3C0, "HVI3C0"); -+FUNC_DECL_(I3C1, "HVI3C1"); -+FUNC_DECL_(I3C2, "HVI3C2"); -+FUNC_DECL_(I3C3, "HVI3C3"); -+FUNC_DECL_(I3C4, "I3C4"); -+FUNC_DECL_(I3C5, "I3C5"); -+FUNC_DECL_(I3C6, "I3C6"); -+FUNC_DECL_(I3C7, "I3C7"); -+FUNC_DECL_(I3C8, "I3C8"); -+FUNC_DECL_(I3C9, "I3C9"); -+FUNC_DECL_(I3C10, "I3C10"); -+FUNC_DECL_(I3C11, "I3C11"); -+FUNC_DECL_(I3C12, "HVI3C12"); -+FUNC_DECL_(I3C13, "HVI3C13"); -+FUNC_DECL_(I3C14, "HVI3C14"); -+FUNC_DECL_(I3C15, "HVI3C15"); -+FUNC_DECL_(LTPI, "LTPI"); -+FUNC_DECL_(SPI0, "SPI0"); -+FUNC_DECL_(QSPI0, "QSPI0"); -+FUNC_DECL_(SPI0CS1, "SPI0CS1"); -+FUNC_DECL_(SPI0ABR, "SPI0ABR"); -+FUNC_DECL_(SPI0WPN, "SPI0WPN"); -+FUNC_DECL_(SPI1, "SPI1"); -+FUNC_DECL_(QSPI1, "QSPI1"); -+FUNC_DECL_(SPI1CS1, "SPI1CS1"); -+FUNC_DECL_(SPI1ABR, "SPI1ABR"); -+FUNC_DECL_(SPI1WPN, "SPI1WPN"); -+FUNC_DECL_(SPI2, "SPI2"); -+FUNC_DECL_(QSPI2, "QSPI2"); -+FUNC_DECL_(SPI2CS1, "SPI2CS1"); -+FUNC_DECL_(THRU2, "THRU2"); -+FUNC_DECL_(THRU3, "THRU3"); -+FUNC_DECL_(JTAGM1, "JTAGM1"); -+FUNC_DECL_(MDIO0, "MDIO0"); -+FUNC_DECL_(MDIO1, "MDIO1"); -+FUNC_DECL_(MDIO2, "MDIO2"); -+FUNC_DECL_(FWQSPI, "FWQSPI"); -+FUNC_DECL_(FWSPIABR, "FWSPIABR"); -+FUNC_DECL_(FWSPIWPN, "FWSPIWPN"); -+FUNC_DECL_(RGMII0, "RGMII0"); -+FUNC_DECL_(RGMII1, "RGMII1"); -+FUNC_DECL_(RMII0, "RMII0"); -+FUNC_DECL_(RMII0RCLKO, "RMII0RCLKO"); -+FUNC_DECL_(RMII1, "RMII1"); -+FUNC_DECL_(RMII1RCLKO, "RMII1RCLKO"); -+FUNC_DECL_(VGA, "VGA"); -+FUNC_DECL_(SGPS, "SGPS"); -+FUNC_DECL_(I2CF0, "I2CF0"); -+FUNC_DECL_(I2CF1, "I2CF1"); -+FUNC_DECL_(I2CF2, "I2CF2"); -+FUNC_DECL_(CANBUS, "CANBUS"); -+FUNC_DECL_(USBUART, "USBUART"); -+FUNC_DECL_(HBLED, "HBLED"); -+FUNC_DECL_(MACLINK0, "MACLINK0"); -+FUNC_DECL_(MACLINK1, "MACLINK1"); -+FUNC_DECL_(MACLINK2, "MACLINK2"); -+FUNC_DECL_(SMON0, "SMON0"); -+FUNC_DECL_(SMON1, "SMON1"); -+FUNC_DECL_(SGMII, "SGMII"); -+FUNC_DECL_(PCIERC, "PE2SGRSTN"); -+FUNC_DECL_(USB2C, "USB2CUD", "USB2CD", "USB2CH", "USB2CU"); -+FUNC_DECL_(USB2D, "USB2DD", "USB2DH"); -+ -+static struct aspeed_pin_function aspeed_g7_soc1_funcs[] = { -+ ASPEED_PINCTRL_FUNC(ESPI0), -+ ASPEED_PINCTRL_FUNC(ESPI1), -+ ASPEED_PINCTRL_FUNC(LPC0), -+ ASPEED_PINCTRL_FUNC(LPC1), -+ ASPEED_PINCTRL_FUNC(VPI), -+ ASPEED_PINCTRL_FUNC(SD), -+ ASPEED_PINCTRL_FUNC(OSCCLK), -+ ASPEED_PINCTRL_FUNC(TACH0), -+ ASPEED_PINCTRL_FUNC(TACH1), -+ ASPEED_PINCTRL_FUNC(TACH2), -+ ASPEED_PINCTRL_FUNC(TACH3), -+ ASPEED_PINCTRL_FUNC(TACH4), -+ ASPEED_PINCTRL_FUNC(TACH5), -+ ASPEED_PINCTRL_FUNC(TACH6), -+ ASPEED_PINCTRL_FUNC(TACH7), -+ ASPEED_PINCTRL_FUNC(THRU0), -+ ASPEED_PINCTRL_FUNC(THRU1), -+ ASPEED_PINCTRL_FUNC(NTCS5), -+ ASPEED_PINCTRL_FUNC(NTCS5), -+ ASPEED_PINCTRL_FUNC(NDSR5), -+ ASPEED_PINCTRL_FUNC(NRI5), -+ ASPEED_PINCTRL_FUNC(NRI5), -+ ASPEED_PINCTRL_FUNC(SALT12), -+ ASPEED_PINCTRL_FUNC(SALT13), -+ ASPEED_PINCTRL_FUNC(SALT14), -+ ASPEED_PINCTRL_FUNC(SALT15), -+ ASPEED_PINCTRL_FUNC(TACH8), -+ ASPEED_PINCTRL_FUNC(TACH9), -+ ASPEED_PINCTRL_FUNC(TACH10), -+ ASPEED_PINCTRL_FUNC(TACH11), -+ ASPEED_PINCTRL_FUNC(TACH12), -+ ASPEED_PINCTRL_FUNC(TACH13), -+ ASPEED_PINCTRL_FUNC(TACH14), -+ ASPEED_PINCTRL_FUNC(TACH15), -+ ASPEED_PINCTRL_FUNC(SPIM0), -+ ASPEED_PINCTRL_FUNC(PWM0), -+ ASPEED_PINCTRL_FUNC(PWM1), -+ ASPEED_PINCTRL_FUNC(PWM2), -+ ASPEED_PINCTRL_FUNC(PWM3), -+ ASPEED_PINCTRL_FUNC(PWM4), -+ ASPEED_PINCTRL_FUNC(PWM5), -+ ASPEED_PINCTRL_FUNC(PWM6), -+ ASPEED_PINCTRL_FUNC(PWM7), -+ ASPEED_PINCTRL_FUNC(SIOPBON0), -+ ASPEED_PINCTRL_FUNC(SIOPBIN0), -+ ASPEED_PINCTRL_FUNC(SIOSCIN0), -+ ASPEED_PINCTRL_FUNC(SIOS3N0), -+ ASPEED_PINCTRL_FUNC(SIOS5N0), -+ ASPEED_PINCTRL_FUNC(SIOPWREQN0), -+ ASPEED_PINCTRL_FUNC(SIOONCTRLN0), -+ ASPEED_PINCTRL_FUNC(SIOPWRGD0), -+ ASPEED_PINCTRL_FUNC(UART0), -+ ASPEED_PINCTRL_FUNC(UART1), -+ ASPEED_PINCTRL_FUNC(UART2), -+ ASPEED_PINCTRL_FUNC(UART3), -+ ASPEED_PINCTRL_FUNC(UART5), -+ ASPEED_PINCTRL_FUNC(UART6), -+ ASPEED_PINCTRL_FUNC(UART7), -+ ASPEED_PINCTRL_FUNC(UART8), -+ ASPEED_PINCTRL_FUNC(UART9), -+ ASPEED_PINCTRL_FUNC(UART10), -+ ASPEED_PINCTRL_FUNC(UART11), -+ ASPEED_PINCTRL_FUNC(SPIM1), -+ ASPEED_PINCTRL_FUNC(PWM7), -+ ASPEED_PINCTRL_FUNC(PWM8), -+ ASPEED_PINCTRL_FUNC(PWM9), -+ ASPEED_PINCTRL_FUNC(PWM10), -+ ASPEED_PINCTRL_FUNC(PWM11), -+ ASPEED_PINCTRL_FUNC(PWM12), -+ ASPEED_PINCTRL_FUNC(PWM13), -+ ASPEED_PINCTRL_FUNC(PWM14), -+ ASPEED_PINCTRL_FUNC(PWM15), -+ ASPEED_PINCTRL_FUNC(WDTRST0N), -+ ASPEED_PINCTRL_FUNC(WDTRST1N), -+ ASPEED_PINCTRL_FUNC(WDTRST2N), -+ ASPEED_PINCTRL_FUNC(WDTRST3N), -+ ASPEED_PINCTRL_FUNC(WDTRST4N), -+ ASPEED_PINCTRL_FUNC(WDTRST5N), -+ ASPEED_PINCTRL_FUNC(WDTRST6N), -+ ASPEED_PINCTRL_FUNC(WDTRST7N), -+ ASPEED_PINCTRL_FUNC(FSI0), -+ ASPEED_PINCTRL_FUNC(FSI1), -+ ASPEED_PINCTRL_FUNC(FSI2), -+ ASPEED_PINCTRL_FUNC(FSI3), -+ ASPEED_PINCTRL_FUNC(SALT0), -+ ASPEED_PINCTRL_FUNC(SALT1), -+ ASPEED_PINCTRL_FUNC(SALT2), -+ ASPEED_PINCTRL_FUNC(SALT3), -+ ASPEED_PINCTRL_FUNC(SALT4), -+ ASPEED_PINCTRL_FUNC(SALT5), -+ ASPEED_PINCTRL_FUNC(SALT6), -+ ASPEED_PINCTRL_FUNC(SALT7), -+ ASPEED_PINCTRL_FUNC(SALT8), -+ ASPEED_PINCTRL_FUNC(SALT9), -+ ASPEED_PINCTRL_FUNC(SALT10), -+ ASPEED_PINCTRL_FUNC(SALT11), -+ ASPEED_PINCTRL_FUNC(ADC0), -+ ASPEED_PINCTRL_FUNC(ADC1), -+ ASPEED_PINCTRL_FUNC(ADC2), -+ ASPEED_PINCTRL_FUNC(ADC3), -+ ASPEED_PINCTRL_FUNC(ADC4), -+ ASPEED_PINCTRL_FUNC(ADC5), -+ ASPEED_PINCTRL_FUNC(ADC6), -+ ASPEED_PINCTRL_FUNC(ADC7), -+ ASPEED_PINCTRL_FUNC(ADC8), -+ ASPEED_PINCTRL_FUNC(ADC9), -+ ASPEED_PINCTRL_FUNC(ADC10), -+ ASPEED_PINCTRL_FUNC(ADC11), -+ ASPEED_PINCTRL_FUNC(ADC12), -+ ASPEED_PINCTRL_FUNC(ADC13), -+ ASPEED_PINCTRL_FUNC(ADC14), -+ ASPEED_PINCTRL_FUNC(ADC15), -+ ASPEED_PINCTRL_FUNC(AUXPWRGOOD0), -+ ASPEED_PINCTRL_FUNC(AUXPWRGOOD1), -+ ASPEED_PINCTRL_FUNC(SGPM0), -+ ASPEED_PINCTRL_FUNC(SGPM1), -+ ASPEED_PINCTRL_FUNC(SPIM2), -+ ASPEED_PINCTRL_FUNC(LTPI_PS_I2C0), -+ ASPEED_PINCTRL_FUNC(LTPI_PS_I2C1), -+ ASPEED_PINCTRL_FUNC(LTPI_PS_I2C2), -+ ASPEED_PINCTRL_FUNC(LTPI_PS_I2C3), -+ ASPEED_PINCTRL_FUNC(I2C0), -+ ASPEED_PINCTRL_FUNC(I2C1), -+ ASPEED_PINCTRL_FUNC(I2C2), -+ ASPEED_PINCTRL_FUNC(I2C3), -+ ASPEED_PINCTRL_FUNC(I2C4), -+ ASPEED_PINCTRL_FUNC(I2C5), -+ ASPEED_PINCTRL_FUNC(I2C6), -+ ASPEED_PINCTRL_FUNC(I2C7), -+ ASPEED_PINCTRL_FUNC(I2C8), -+ ASPEED_PINCTRL_FUNC(I2C9), -+ ASPEED_PINCTRL_FUNC(I2C10), -+ ASPEED_PINCTRL_FUNC(I2C11), -+ ASPEED_PINCTRL_FUNC(I2C12), -+ ASPEED_PINCTRL_FUNC(I2C13), -+ ASPEED_PINCTRL_FUNC(I2C14), -+ ASPEED_PINCTRL_FUNC(I2C15), -+ ASPEED_PINCTRL_FUNC(SIOPBON1), -+ ASPEED_PINCTRL_FUNC(SIOPBIN1), -+ ASPEED_PINCTRL_FUNC(SIOSCIN1), -+ ASPEED_PINCTRL_FUNC(SIOS3N1), -+ ASPEED_PINCTRL_FUNC(SIOS5N1), -+ ASPEED_PINCTRL_FUNC(SIOPWREQN1), -+ ASPEED_PINCTRL_FUNC(SIOONCTRLN1), -+ ASPEED_PINCTRL_FUNC(SIOPWRGD1), -+ ASPEED_PINCTRL_FUNC(I3C0), -+ ASPEED_PINCTRL_FUNC(I3C1), -+ ASPEED_PINCTRL_FUNC(I3C2), -+ ASPEED_PINCTRL_FUNC(I3C3), -+ ASPEED_PINCTRL_FUNC(I3C4), -+ ASPEED_PINCTRL_FUNC(I3C5), -+ ASPEED_PINCTRL_FUNC(I3C6), -+ ASPEED_PINCTRL_FUNC(I3C7), -+ ASPEED_PINCTRL_FUNC(I3C8), -+ ASPEED_PINCTRL_FUNC(I3C9), -+ ASPEED_PINCTRL_FUNC(I3C10), -+ ASPEED_PINCTRL_FUNC(I3C11), -+ ASPEED_PINCTRL_FUNC(I3C12), -+ ASPEED_PINCTRL_FUNC(I3C13), -+ ASPEED_PINCTRL_FUNC(I3C14), -+ ASPEED_PINCTRL_FUNC(I3C15), -+ ASPEED_PINCTRL_FUNC(LTPI), -+ ASPEED_PINCTRL_FUNC(SPI0), -+ ASPEED_PINCTRL_FUNC(QSPI0), -+ ASPEED_PINCTRL_FUNC(SPI0CS1), -+ ASPEED_PINCTRL_FUNC(SPI0ABR), -+ ASPEED_PINCTRL_FUNC(SPI0WPN), -+ ASPEED_PINCTRL_FUNC(SPI1), -+ ASPEED_PINCTRL_FUNC(QSPI1), -+ ASPEED_PINCTRL_FUNC(SPI1CS1), -+ ASPEED_PINCTRL_FUNC(SPI1ABR), -+ ASPEED_PINCTRL_FUNC(SPI1WPN), -+ ASPEED_PINCTRL_FUNC(SPI2), -+ ASPEED_PINCTRL_FUNC(QSPI2), -+ ASPEED_PINCTRL_FUNC(SPI2CS1), -+ ASPEED_PINCTRL_FUNC(THRU2), -+ ASPEED_PINCTRL_FUNC(THRU3), -+ ASPEED_PINCTRL_FUNC(JTAGM1), -+ ASPEED_PINCTRL_FUNC(MDIO0), -+ ASPEED_PINCTRL_FUNC(MDIO1), -+ ASPEED_PINCTRL_FUNC(MDIO2), -+ ASPEED_PINCTRL_FUNC(FWQSPI), -+ ASPEED_PINCTRL_FUNC(FWSPIABR), -+ ASPEED_PINCTRL_FUNC(FWSPIWPN), -+ ASPEED_PINCTRL_FUNC(RGMII0), -+ ASPEED_PINCTRL_FUNC(RGMII1), -+ ASPEED_PINCTRL_FUNC(RMII0), -+ ASPEED_PINCTRL_FUNC(RMII0RCLKO), -+ ASPEED_PINCTRL_FUNC(RMII1), -+ ASPEED_PINCTRL_FUNC(RMII1RCLKO), -+ ASPEED_PINCTRL_FUNC(VGA), -+ ASPEED_PINCTRL_FUNC(SGPS), -+ ASPEED_PINCTRL_FUNC(I2CF0), -+ ASPEED_PINCTRL_FUNC(I2CF1), -+ ASPEED_PINCTRL_FUNC(I2CF2), -+ ASPEED_PINCTRL_FUNC(CANBUS), -+ ASPEED_PINCTRL_FUNC(USBUART), -+ ASPEED_PINCTRL_FUNC(HBLED), -+ ASPEED_PINCTRL_FUNC(MACLINK0), -+ ASPEED_PINCTRL_FUNC(MACLINK1), -+ ASPEED_PINCTRL_FUNC(MACLINK2), -+ ASPEED_PINCTRL_FUNC(SMON0), -+ ASPEED_PINCTRL_FUNC(SMON1), -+ ASPEED_PINCTRL_FUNC(SGMII), -+ ASPEED_PINCTRL_FUNC(PCIERC), -+ ASPEED_PINCTRL_FUNC(USB2C), -+ ASPEED_PINCTRL_FUNC(USB2D), -+}; -+ -+/* number, name, drv_data */ -+static const struct pinctrl_pin_desc aspeed_g7_soc1_pins[] = { -+ PINCTRL_PIN(C16, "C16"), -+ PINCTRL_PIN(C14, "C14"), -+ PINCTRL_PIN(C11, "C11"), -+ PINCTRL_PIN(D9, "D9"), -+ PINCTRL_PIN(F14, "F14"), -+ PINCTRL_PIN(D10, "D10"), -+ PINCTRL_PIN(C12, "C12"), -+ PINCTRL_PIN(C13, "C13"), -+ PINCTRL_PIN(AC26, "AC26"), -+ PINCTRL_PIN(AA25, "AA25"), -+ PINCTRL_PIN(AB23, "AB23"), -+ PINCTRL_PIN(U22, "U22"), -+ PINCTRL_PIN(V21, "V21"), -+ PINCTRL_PIN(N26, "N26"), -+ PINCTRL_PIN(P25, "P25"), -+ PINCTRL_PIN(N25, "N25"), -+ PINCTRL_PIN(V23, "V23"), -+ PINCTRL_PIN(W22, "W22"), -+ PINCTRL_PIN(AB26, "AB26"), -+ PINCTRL_PIN(AD26, "AD26"), -+ PINCTRL_PIN(P26, "P26"), -+ PINCTRL_PIN(AE26, "AE26"), -+ PINCTRL_PIN(AF26, "AF26"), -+ PINCTRL_PIN(AF25, "AF25"), -+ PINCTRL_PIN(AE25, "AE25"), -+ PINCTRL_PIN(AD25, "AD25"), -+ PINCTRL_PIN(AF23, "AF23"), -+ PINCTRL_PIN(AF20, "AF20"), -+ PINCTRL_PIN(AF21, "AF21"), -+ PINCTRL_PIN(AE21, "AE21"), -+ PINCTRL_PIN(AE23, "AE23"), -+ PINCTRL_PIN(AD22, "AD22"), -+ PINCTRL_PIN(AF17, "AF17"), -+ PINCTRL_PIN(AA16, "AA16"), -+ PINCTRL_PIN(Y16, "Y16"), -+ PINCTRL_PIN(V17, "V17"), -+ PINCTRL_PIN(J13, "J13"), -+ PINCTRL_PIN(AB16, "AB16"), -+ PINCTRL_PIN(AC16, "AC16"), -+ PINCTRL_PIN(AF16, "AF16"), -+ PINCTRL_PIN(AA15, "AA15"), -+ PINCTRL_PIN(AB15, "AB15"), -+ PINCTRL_PIN(AC15, "AC15"), -+ PINCTRL_PIN(AD15, "AD15"), -+ PINCTRL_PIN(Y15, "Y15"), -+ PINCTRL_PIN(AA14, "AA14"), -+ PINCTRL_PIN(W16, "W16"), -+ PINCTRL_PIN(V16, "V16"), -+ PINCTRL_PIN(AB18, "AB18"), -+ PINCTRL_PIN(AC18, "AC18"), -+ PINCTRL_PIN(K13, "K13"), -+ PINCTRL_PIN(AA17, "AA17"), -+ PINCTRL_PIN(AB17, "AB17"), -+ PINCTRL_PIN(AD16, "AD16"), -+ PINCTRL_PIN(AC17, "AC17"), -+ PINCTRL_PIN(AD17, "AD17"), -+ PINCTRL_PIN(AE16, "AE16"), -+ PINCTRL_PIN(AE17, "AE17"), -+ PINCTRL_PIN(AB24, "AB24"), -+ PINCTRL_PIN(W26, "W26"), -+ PINCTRL_PIN(HOLE0, "HOLE0"), -+ PINCTRL_PIN(HOLE1, "HOLE1"), -+ PINCTRL_PIN(HOLE2, "HOLE2"), -+ PINCTRL_PIN(HOLE3, "HOLE3"), -+ PINCTRL_PIN(W25, "W25"), -+ PINCTRL_PIN(Y23, "Y23"), -+ PINCTRL_PIN(Y24, "Y24"), -+ PINCTRL_PIN(W21, "W21"), -+ PINCTRL_PIN(AA23, "AA23"), -+ PINCTRL_PIN(AC22, "AC22"), -+ PINCTRL_PIN(AB22, "AB22"), -+ PINCTRL_PIN(Y21, "Y21"), -+ PINCTRL_PIN(AE20, "AE20"), -+ PINCTRL_PIN(AF19, "AF19"), -+ PINCTRL_PIN(Y22, "Y22"), -+ PINCTRL_PIN(AA20, "AA20"), -+ PINCTRL_PIN(AA22, "AA22"), -+ PINCTRL_PIN(AB20, "AB20"), -+ PINCTRL_PIN(AF18, "AF18"), -+ PINCTRL_PIN(AE19, "AE19"), -+ PINCTRL_PIN(AD20, "AD20"), -+ PINCTRL_PIN(AC20, "AC20"), -+ PINCTRL_PIN(AA21, "AA21"), -+ PINCTRL_PIN(AB21, "AB21"), -+ PINCTRL_PIN(AC19, "AC19"), -+ PINCTRL_PIN(AE18, "AE18"), -+ PINCTRL_PIN(AD19, "AD19"), -+ PINCTRL_PIN(AD18, "AD18"), -+ PINCTRL_PIN(U25, "U25"), -+ PINCTRL_PIN(U26, "U26"), -+ PINCTRL_PIN(Y26, "Y26"), -+ PINCTRL_PIN(AA24, "AA24"), -+ PINCTRL_PIN(R25, "R25"), -+ PINCTRL_PIN(AA26, "AA26"), -+ PINCTRL_PIN(R26, "R26"), -+ PINCTRL_PIN(Y25, "Y25"), -+ PINCTRL_PIN(B16, "B16"), -+ PINCTRL_PIN(D14, "D14"), -+ PINCTRL_PIN(B15, "B15"), -+ PINCTRL_PIN(B14, "B14"), -+ PINCTRL_PIN(C17, "C17"), -+ PINCTRL_PIN(B13, "B13"), -+ PINCTRL_PIN(E14, "E14"), -+ PINCTRL_PIN(C15, "C15"), -+ PINCTRL_PIN(D24, "D24"), -+ PINCTRL_PIN(B23, "B23"), -+ PINCTRL_PIN(B22, "B22"), -+ PINCTRL_PIN(C23, "C23"), -+ PINCTRL_PIN(B18, "B18"), -+ PINCTRL_PIN(B21, "B21"), -+ PINCTRL_PIN(M15, "M15"), -+ PINCTRL_PIN(B19, "B19"), -+ PINCTRL_PIN(B26, "B26"), -+ PINCTRL_PIN(A25, "A25"), -+ PINCTRL_PIN(A24, "A24"), -+ PINCTRL_PIN(B24, "B24"), -+ PINCTRL_PIN(E26, "E26"), -+ PINCTRL_PIN(A21, "A21"), -+ PINCTRL_PIN(A19, "A19"), -+ PINCTRL_PIN(A18, "A18"), -+ PINCTRL_PIN(D26, "D26"), -+ PINCTRL_PIN(C26, "C26"), -+ PINCTRL_PIN(A23, "A23"), -+ PINCTRL_PIN(A22, "A22"), -+ PINCTRL_PIN(B25, "B25"), -+ PINCTRL_PIN(F26, "F26"), -+ PINCTRL_PIN(A26, "A26"), -+ PINCTRL_PIN(A14, "A14"), -+ PINCTRL_PIN(E10, "E10"), -+ PINCTRL_PIN(E13, "E13"), -+ PINCTRL_PIN(D12, "D12"), -+ PINCTRL_PIN(F10, "F10"), -+ PINCTRL_PIN(E11, "E11"), -+ PINCTRL_PIN(F11, "F11"), -+ PINCTRL_PIN(F13, "F13"), -+ PINCTRL_PIN(N15, "N15"), -+ PINCTRL_PIN(C20, "C20"), -+ PINCTRL_PIN(C19, "C19"), -+ PINCTRL_PIN(A8, "A8"), -+ PINCTRL_PIN(R14, "R14"), -+ PINCTRL_PIN(A7, "A7"), -+ PINCTRL_PIN(P14, "P14"), -+ PINCTRL_PIN(D20, "D20"), -+ PINCTRL_PIN(A6, "A6"), -+ PINCTRL_PIN(B6, "B6"), -+ PINCTRL_PIN(N14, "N14"), -+ PINCTRL_PIN(B7, "B7"), -+ PINCTRL_PIN(B8, "B8"), -+ PINCTRL_PIN(B9, "B9"), -+ PINCTRL_PIN(M14, "M14"), -+ PINCTRL_PIN(J11, "J11"), -+ PINCTRL_PIN(E7, "E7"), -+ PINCTRL_PIN(D19, "D19"), -+ PINCTRL_PIN(B11, "B11"), -+ PINCTRL_PIN(D15, "D15"), -+ PINCTRL_PIN(B12, "B12"), -+ PINCTRL_PIN(B10, "B10"), -+ PINCTRL_PIN(P13, "P13"), -+ PINCTRL_PIN(C18, "C18"), -+ PINCTRL_PIN(C6, "C6"), -+ PINCTRL_PIN(C7, "C7"), -+ PINCTRL_PIN(D7, "D7"), -+ PINCTRL_PIN(N13, "N13"), -+ PINCTRL_PIN(C8, "C8"), -+ PINCTRL_PIN(C9, "C9"), -+ PINCTRL_PIN(C10, "C10"), -+ PINCTRL_PIN(M16, "M16"), -+ PINCTRL_PIN(A15, "A15"), -+ PINCTRL_PIN(G11, "G11"), -+ PINCTRL_PIN(H7, "H7"), -+ PINCTRL_PIN(H8, "H8"), -+ PINCTRL_PIN(H9, "H9"), -+ PINCTRL_PIN(H10, "H10"), -+ PINCTRL_PIN(H11, "H11"), -+ PINCTRL_PIN(J9, "J9"), -+ PINCTRL_PIN(J10, "J10"), -+ PINCTRL_PIN(E9, "E9"), -+ PINCTRL_PIN(F9, "F9"), -+ PINCTRL_PIN(F8, "F8"), -+ PINCTRL_PIN(M13, "M13"), -+ PINCTRL_PIN(F7, "F7"), -+ PINCTRL_PIN(D8, "D8"), -+ PINCTRL_PIN(E8, "E8"), -+ PINCTRL_PIN(L12, "L12"), -+ PINCTRL_PIN(F12, "F12"), -+ PINCTRL_PIN(E12, "E12"), -+ PINCTRL_PIN(J12, "J12"), -+ PINCTRL_PIN(G7, "G7"), -+ PINCTRL_PIN(G8, "G8"), -+ PINCTRL_PIN(G9, "G9"), -+ PINCTRL_PIN(G10, "G10"), -+ PINCTRL_PIN(K12, "K12"), -+ PINCTRL_PIN(W17, "W17"), -+ PINCTRL_PIN(V18, "V18"), -+ PINCTRL_PIN(W18, "W18"), -+ PINCTRL_PIN(Y17, "Y17"), -+ PINCTRL_PIN(AA18, "AA18"), -+ PINCTRL_PIN(AA13, "AA13"), -+ PINCTRL_PIN(Y18, "Y18"), -+ PINCTRL_PIN(AA12, "AA12"), -+ PINCTRL_PIN(W20, "W20"), -+ PINCTRL_PIN(V20, "V20"), -+ PINCTRL_PIN(Y11, "Y11"), -+ PINCTRL_PIN(V14, "V14"), -+ PINCTRL_PIN(V19, "V19"), -+ PINCTRL_PIN(W14, "W14"), -+ PINCTRL_PIN(Y20, "Y20"), -+ PINCTRL_PIN(AB19, "AB19"), -+ PINCTRL_PIN(U21, "U21"), -+ PINCTRL_PIN(T24, "T24"), -+ PINCTRL_PIN(V24, "V24"), -+ PINCTRL_PIN(V22, "V22"), -+ PINCTRL_PIN(T23, "T23"), -+ PINCTRL_PIN(AC25, "AC25"), -+ PINCTRL_PIN(AB25, "AB25"), -+ PINCTRL_PIN(AC24, "AC24"), -+ PINCTRL_PIN(SGMII0, "SGMII0"), -+ PINCTRL_PIN(PCIERC2_PERST, "PCIERC2_PERST"), -+ PINCTRL_PIN(PORTC_MODE, "PORTC_MODE"), -+ PINCTRL_PIN(PORTD_MODE, "PORTD_MODE"), -+}; -+ -+FUNCFG_DESCL(C16, PIN_CFG(ESPI1, SCU400, GENMASK(2, 0), 1), -+ PIN_CFG(LPC1, SCU400, GENMASK(2, 0), 2), -+ PIN_CFG(SD, SCU400, GENMASK(2, 0), 3), -+ PIN_CFG(DI2C0, SCU400, GENMASK(2, 0), 4), -+ PIN_CFG(VPI, SCU400, GENMASK(2, 0), 5)); -+FUNCFG_DESCL(C14, PIN_CFG(ESPI1, SCU400, GENMASK(6, 4), (1 << 4)), -+ PIN_CFG(LPC1, SCU400, GENMASK(6, 4), (2 << 4)), -+ PIN_CFG(SD, SCU400, GENMASK(6, 4), (3 << 4)), -+ PIN_CFG(DI2C1, SCU400, GENMASK(6, 4), (4 << 4)), -+ PIN_CFG(VPI, SCU400, GENMASK(6, 4), (5 << 4))); -+FUNCFG_DESCL(C11, PIN_CFG(ESPI1, SCU400, GENMASK(10, 8), (1 << 8)), -+ PIN_CFG(LPC1, SCU400, GENMASK(10, 8), (2 << 8)), -+ PIN_CFG(SD, SCU400, GENMASK(10, 8), (3 << 8)), -+ PIN_CFG(DI2C3, SCU400, GENMASK(10, 8), (4 << 8)), -+ PIN_CFG(VPI, SCU400, GENMASK(10, 8), (5 << 8))); -+FUNCFG_DESCL(D9, PIN_CFG(ESPI1, SCU400, GENMASK(14, 12), (1 << 12)), -+ PIN_CFG(LPC1, SCU400, GENMASK(14, 12), (2 << 12)), -+ PIN_CFG(SD, SCU400, GENMASK(14, 12), (3 << 12)), -+ PIN_CFG(DI2C0, SCU400, GENMASK(14, 12), (4 << 12)), -+ PIN_CFG(VPI, SCU400, GENMASK(14, 12), (5 << 12))); -+FUNCFG_DESCL(F14, PIN_CFG(ESPI1, SCU400, GENMASK(18, 16), (1 << 16)), -+ PIN_CFG(LPC1, SCU400, GENMASK(18, 16), (2 << 16)), -+ PIN_CFG(SD, SCU400, GENMASK(18, 16), (3 << 16)), -+ PIN_CFG(DI2C1, SCU400, GENMASK(18, 16), (4 << 16)), -+ PIN_CFG(VPI, SCU400, GENMASK(18, 16), (5 << 16))); -+FUNCFG_DESCL(D10, PIN_CFG(ESPI1, SCU400, GENMASK(22, 20), (1 << 20)), -+ PIN_CFG(LPC1, SCU400, GENMASK(22, 20), (2 << 20)), -+ PIN_CFG(SD, SCU400, GENMASK(22, 20), (3 << 20)), -+ PIN_CFG(DI2C2, SCU400, GENMASK(22, 20), (4 << 20)), -+ PIN_CFG(VPI, SCU400, GENMASK(22, 20), (5 << 20))); -+FUNCFG_DESCL(C12, PIN_CFG(ESPI1, SCU400, GENMASK(26, 24), (1 << 24)), -+ PIN_CFG(LPC1, SCU400, GENMASK(26, 24), (2 << 24)), -+ PIN_CFG(SD, SCU400, GENMASK(26, 24), (3 << 24)), -+ PIN_CFG(DI2C2, SCU400, GENMASK(26, 24), (4 << 24))); -+FUNCFG_DESCL(C13, PIN_CFG(ESPI1, SCU400, GENMASK(30, 28), (1 << 28)), -+ PIN_CFG(LPC1, SCU400, GENMASK(30, 28), (2 << 28)), -+ PIN_CFG(SD, SCU400, GENMASK(30, 28), (3 << 28)), -+ PIN_CFG(DI2C3, SCU400, GENMASK(30, 28), (4 << 28))); -+FUNCFG_DESCL(AC26, PIN_CFG(TACH0, SCU404, GENMASK(2, 0), 1), -+ PIN_CFG(THRU0, SCU404, GENMASK(2, 0), 2), -+ PIN_CFG(VPI, SCU404, GENMASK(2, 0), 3)); -+FUNCFG_DESCL(AA25, PIN_CFG(TACH1, SCU404, GENMASK(6, 4), (1 << 4)), -+ PIN_CFG(THRU0, SCU404, GENMASK(6, 4), (2 << 4)), -+ PIN_CFG(VPI, SCU404, GENMASK(6, 4), (3 << 4))); -+FUNCFG_DESCL(AB23, PIN_CFG(TACH2, SCU404, GENMASK(10, 8), (1 << 8)), -+ PIN_CFG(THRU1, SCU404, GENMASK(10, 8), (2 << 8)), -+ PIN_CFG(VPI, SCU404, GENMASK(10, 8), (3 << 8))); -+FUNCFG_DESCL(U22, PIN_CFG(TACH3, SCU404, GENMASK(14, 12), (1 << 12)), -+ PIN_CFG(THRU1, SCU404, GENMASK(14, 12), (2 << 12)), -+ PIN_CFG(VPI, SCU404, GENMASK(14, 12), (3 << 12))); -+FUNCFG_DESCL(V21, PIN_CFG(TACH4, SCU404, GENMASK(18, 16), (1 << 16)), -+ PIN_CFG(VPI, SCU404, GENMASK(18, 16), (3 << 16)), -+ PIN_CFG(NCTS5, SCU404, GENMASK(18, 16), (4 << 16))); -+FUNCFG_DESCL(N26, PIN_CFG(TACH5, SCU404, GENMASK(22, 20), (1 << 20)), -+ PIN_CFG(VPI, SCU404, GENMASK(22, 20), (3 << 20)), -+ PIN_CFG(NDCD5, SCU404, GENMASK(22, 20), (4 << 20))); -+FUNCFG_DESCL(P25, PIN_CFG(TACH6, SCU404, GENMASK(26, 24), (1 << 24)), -+ PIN_CFG(VPI, SCU404, GENMASK(26, 24), (3 << 24)), -+ PIN_CFG(NDSR5, SCU404, GENMASK(26, 24), (4 << 24))); -+FUNCFG_DESCL(N25, PIN_CFG(TACH7, SCU404, GENMASK(30, 28), (1 << 28)), -+ PIN_CFG(VPI, SCU404, GENMASK(30, 28), (3 << 28)), -+ PIN_CFG(NRI5, SCU404, GENMASK(30, 28), (4 << 28))); -+FUNCFG_DESCL(V23, PIN_CFG(TACH8, SCU408, GENMASK(2, 0), 1), -+ PIN_CFG(VPI, SCU408, GENMASK(2, 0), 3), -+ PIN_CFG(NDTR5, SCU408, GENMASK(2, 0), 4)); -+FUNCFG_DESCL(W22, PIN_CFG(TACH9, SCU408, GENMASK(6, 4), (1 << 4)), -+ PIN_CFG(VPI, SCU408, GENMASK(6, 4), (3 << 4)), -+ PIN_CFG(NRTS5, SCU408, GENMASK(6, 4), (4 << 4))); -+FUNCFG_DESCL(AB26, PIN_CFG(TACH10, SCU408, GENMASK(10, 8), (1 << 8)), -+ PIN_CFG(SALT12, SCU408, GENMASK(10, 8), (2 << 8)), -+ PIN_CFG(VPI, SCU408, GENMASK(10, 8), (3 << 8)), -+ PIN_CFG(NCTS6, SCU408, GENMASK(10, 8), (4 << 8))); -+FUNCFG_DESCL(AD26, PIN_CFG(TACH11, SCU408, GENMASK(14, 12), (1 << 12)), -+ PIN_CFG(SALT13, SCU408, GENMASK(14, 12), (2 << 12)), -+ PIN_CFG(VPI, SCU408, GENMASK(14, 12), (3 << 12)), -+ PIN_CFG(NDCD6, SCU408, GENMASK(14, 12), (4 << 12))); -+FUNCFG_DESCL(P26, PIN_CFG(TACH12, SCU408, GENMASK(18, 16), (1 << 16)), -+ PIN_CFG(SALT14, SCU408, GENMASK(18, 16), (2 << 16)), -+ PIN_CFG(VPI, SCU408, GENMASK(18, 16), (3 << 16)), -+ PIN_CFG(NDSR6, SCU408, GENMASK(18, 16), (4 << 16))); -+FUNCFG_DESCL(AE26, PIN_CFG(TACH13, SCU408, GENMASK(22, 20), (1 << 20)), -+ PIN_CFG(SALT15, SCU408, GENMASK(22, 20), (2 << 20)), -+ PIN_CFG(VPI, SCU408, GENMASK(22, 20), (3 << 20)), -+ PIN_CFG(NRI6, SCU408, GENMASK(22, 20), (4 << 20))); -+FUNCFG_DESCL(AF26, PIN_CFG(TACH14, SCU408, GENMASK(26, 24), (1 << 24)), -+ PIN_CFG(LPC0, SCU408, GENMASK(26, 24), (2 << 24)), -+ PIN_CFG(VPI, SCU408, GENMASK(26, 24), (3 << 24)), -+ PIN_CFG(NDTR6, SCU408, GENMASK(26, 24), (4 << 24))); -+FUNCFG_DESCL(AF25, PIN_CFG(TACH15, SCU408, GENMASK(30, 28), (1 << 28)), -+ PIN_CFG(LPC0, SCU408, GENMASK(30, 28), (2 << 28)), -+ PIN_CFG(VPI, SCU408, GENMASK(30, 28), (3 << 28)), -+ PIN_CFG(NRTS6, SCU408, GENMASK(30, 28), (4 << 28))); -+FUNCFG_DESCL(AE25, PIN_CFG(PWM0, SCU40C, GENMASK(2, 0), 1), -+ PIN_CFG(SIOPBON0, SCU40C, GENMASK(2, 0), 2), -+ PIN_CFG(VPI, SCU40C, GENMASK(2, 0), 3), -+ PIN_CFG(SPIM0, SCU40C, GENMASK(2, 0), 4)); -+FUNCFG_DESCL(AD25, PIN_CFG(PWM1, SCU40C, GENMASK(6, 4), (1 << 4)), -+ PIN_CFG(SIOPBIN0, SCU40C, GENMASK(6, 4), (2 << 4)), -+ PIN_CFG(VPI, SCU40C, GENMASK(6, 4), (3 << 4)), -+ PIN_CFG(SPIM0, SCU40C, GENMASK(6, 4), (4 << 4))); -+FUNCFG_DESCL(AF23, PIN_CFG(PWM2, SCU40C, GENMASK(10, 8), (1 << 8)), -+ PIN_CFG(SIOSCIN0, SCU40C, GENMASK(10, 8), (2 << 8)), -+ PIN_CFG(VPI, SCU40C, GENMASK(10, 8), (3 << 8)), -+ PIN_CFG(SPIM0, SCU40C, GENMASK(10, 8), (4 << 8))); -+FUNCFG_DESCL(AF20, PIN_CFG(PWM3, SCU40C, GENMASK(14, 12), (1 << 12)), -+ PIN_CFG(SIOS3N0, SCU40C, GENMASK(14, 12), (2 << 12)), -+ PIN_CFG(VPI, SCU40C, GENMASK(14, 12), (3 << 12)), -+ PIN_CFG(SPIM0, SCU40C, GENMASK(14, 12), (4 << 12))); -+FUNCFG_DESCL(AF21, PIN_CFG(PWM4, SCU40C, GENMASK(18, 16), (1 << 16)), -+ PIN_CFG(SIOS5N0, SCU40C, GENMASK(18, 16), (2 << 16)), -+ PIN_CFG(VPI, SCU40C, GENMASK(18, 16), (3 << 16)), -+ PIN_CFG(SPIM0, SCU40C, GENMASK(18, 16), (4 << 16))); -+FUNCFG_DESCL(AE21, PIN_CFG(PWM5, SCU40C, GENMASK(22, 20), (1 << 20)), -+ PIN_CFG(SIOPWREQN0, SCU40C, GENMASK(22, 20), (2 << 20)), -+ PIN_CFG(VPI, SCU40C, GENMASK(22, 20), (3 << 20)), -+ PIN_CFG(SPIM0, SCU40C, GENMASK(22, 20), (4 << 20))); -+FUNCFG_DESCL(AE23, PIN_CFG(PWM6, SCU40C, GENMASK(26, 24), (1 << 24)), -+ PIN_CFG(SIOONCTRLN0, SCU40C, GENMASK(26, 24), (2 << 24)), -+ PIN_CFG(SPIM0, SCU40C, GENMASK(26, 24), (4 << 24))); -+FUNCFG_DESCL(AD22, PIN_CFG(PWM7, SCU40C, GENMASK(30, 28), (1 << 28)), -+ PIN_CFG(SPIM0, SCU40C, GENMASK(30, 28), (4 << 28))); -+FUNCFG_DESCL(AF17, PIN_CFG(NCTS0, SCU410, GENMASK(2, 0), 1), -+ PIN_CFG(SIOPBON1, SCU410, GENMASK(2, 0), 2)); -+FUNCFG_DESCL(AA16, PIN_CFG(NDCD0, SCU410, GENMASK(6, 4), (1 << 4)), -+ PIN_CFG(SIOPBIN1, SCU410, GENMASK(6, 4), (2 << 4))); -+FUNCFG_DESCL(Y16, PIN_CFG(NDSR0, SCU410, GENMASK(10, 8), (1 << 8)), -+ PIN_CFG(SIOSCIN1, SCU410, GENMASK(10, 8), (2 << 8))); -+FUNCFG_DESCL(V17, PIN_CFG(NRI0, SCU410, GENMASK(14, 12), (1 << 12)), -+ PIN_CFG(SIOS3N1, SCU410, GENMASK(14, 12), (2 << 12))); -+FUNCFG_DESCL(J13, PIN_CFG(NDTR0, SCU410, GENMASK(18, 16), (1 << 16)), -+ PIN_CFG(SIOS5N1, SCU410, GENMASK(18, 16), (2 << 16))); -+FUNCFG_DESCL(AB16, PIN_CFG(NRTS0, SCU410, GENMASK(22, 20), (1 << 20)), -+ PIN_CFG(SIOPWREQN1, SCU410, GENMASK(22, 20), (2 << 20))); -+FUNCFG_DESCL(AC16, PIN_CFG(TXD0, SCU410, GENMASK(26, 24), (1 << 24))); -+FUNCFG_DESCL(AF16, PIN_CFG(RXD0, SCU410, GENMASK(30, 28), (1 << 28))); -+FUNCFG_DESCL(AA15, PIN_CFG(NCTS1, SCU414, GENMASK(2, 0), 1), -+ PIN_CFG(SIOONCTRLN1, SCU414, GENMASK(2, 0), 2)); -+FUNCFG_DESCL(AB15, PIN_CFG(NDCD1, SCU414, GENMASK(6, 4), (1 << 4)), -+ PIN_CFG(SIOPWRGD1, SCU414, GENMASK(6, 4), (2 << 4))); -+FUNCFG_DESCL(AC15, PIN_CFG(NDSR1, SCU414, GENMASK(10, 8), (1 << 8)), -+ PIN_CFG(SALT2, SCU414, GENMASK(10, 8), (2 << 8))); -+FUNCFG_DESCL(AD15, PIN_CFG(NRI1, SCU414, GENMASK(14, 12), (1 << 12)), -+ PIN_CFG(SALT3, SCU414, GENMASK(14, 12), (2 << 12))); -+FUNCFG_DESCL(Y15, PIN_CFG(NDTR1, SCU414, GENMASK(18, 16), (1 << 16))); -+FUNCFG_DESCL(AA14, PIN_CFG(NRTS1, SCU414, GENMASK(22, 20), (1 << 20))); -+FUNCFG_DESCL(W16, PIN_CFG(TXD1, SCU414, GENMASK(26, 24), (1 << 24))); -+FUNCFG_DESCL(V16, PIN_CFG(RXD1, SCU414, GENMASK(30, 28), (1 << 28))); -+FUNCFG_DESCL(AB18, PIN_CFG(TXD2, SCU418, GENMASK(2, 0), 1)); -+FUNCFG_DESCL(AC18, PIN_CFG(RXD2, SCU418, GENMASK(6, 4), (1 << 4)), -+ PIN_CFG(I2C12, SCU418, GENMASK(6, 4), (4 << 4))); -+FUNCFG_DESCL(K13, PIN_CFG(TXD3, SCU418, GENMASK(10, 8), (1 << 8)), -+ PIN_CFG(WDTRST0N, SCU418, GENMASK(10, 8), (2 << 8)), -+ PIN_CFG(PWM8, SCU418, GENMASK(10, 8), (3 << 8)), -+ PIN_CFG(SPIM1, SCU418, GENMASK(10, 8), (5 << 8))); -+FUNCFG_DESCL(AA17, PIN_CFG(RXD3, SCU418, GENMASK(14, 12), (1 << 12)), -+ PIN_CFG(WDTRST1N, SCU418, GENMASK(14, 12), (2 << 12)), -+ PIN_CFG(PWM9, SCU418, GENMASK(14, 12), (3 << 12)), -+ PIN_CFG(I2C12, SCU418, GENMASK(14, 12), (4 << 12)), -+ PIN_CFG(SPIM1, SCU418, GENMASK(14, 12), (5 << 12))); -+FUNCFG_DESCL(AB17, PIN_CFG(TXD5, SCU418, GENMASK(18, 16), (1 << 16)), -+ PIN_CFG(WDTRST2N, SCU418, GENMASK(18, 16), (2 << 16)), -+ PIN_CFG(PWM10, SCU418, GENMASK(18, 16), (3 << 16)), -+ PIN_CFG(I2C13, SCU418, GENMASK(18, 16), (4 << 16)), -+ PIN_CFG(SPIM1, SCU418, GENMASK(18, 16), (5 << 16))); -+FUNCFG_DESCL(AD16, PIN_CFG(RXD5, SCU418, GENMASK(22, 20), (1 << 20)), -+ PIN_CFG(WDTRST3N, SCU418, GENMASK(22, 20), (2 << 20)), -+ PIN_CFG(PWM11, SCU418, GENMASK(22, 20), (3 << 20)), -+ PIN_CFG(I2C13, SCU418, GENMASK(22, 20), (4 << 20)), -+ PIN_CFG(SPIM1, SCU418, GENMASK(22, 20), (5 << 20))); -+FUNCFG_DESCL(AC17, PIN_CFG(TXD6, SCU418, GENMASK(26, 24), (1 << 24)), -+ PIN_CFG(SALT0, SCU418, GENMASK(26, 24), (2 << 24)), -+ PIN_CFG(PWM12, SCU418, GENMASK(26, 24), (3 << 24)), -+ PIN_CFG(I2C14, SCU418, GENMASK(26, 24), (4 << 24)), -+ PIN_CFG(SPIM1, SCU418, GENMASK(26, 24), (5 << 24))); -+FUNCFG_DESCL(AD17, PIN_CFG(RXD6, SCU418, GENMASK(30, 28), (1 << 28)), -+ PIN_CFG(SALT1, SCU418, GENMASK(30, 28), (2 << 28)), -+ PIN_CFG(PWM13, SCU418, GENMASK(30, 28), (3 << 28)), -+ PIN_CFG(I2C14, SCU418, GENMASK(30, 28), (4 << 28)), -+ PIN_CFG(SPIM1, SCU418, GENMASK(30, 28), (5 << 28))); -+FUNCFG_DESCL(AE16, PIN_CFG(TXD7, SCU41C, GENMASK(2, 0), 1), -+ PIN_CFG(I2C15, SCU41C, GENMASK(2, 0), 2), -+ PIN_CFG(PWM14, SCU41C, GENMASK(2, 0), 3), -+ PIN_CFG(LPC1, SCU41C, GENMASK(2, 0), 4), -+ PIN_CFG(SPIM1, SCU41C, GENMASK(2, 0), 5)); -+FUNCFG_DESCL(AE17, PIN_CFG(RXD7, SCU41C, GENMASK(6, 4), (1 << 4)), -+ PIN_CFG(I2C15, SCU41C, GENMASK(6, 4), (2 << 4)), -+ PIN_CFG(PWM15, SCU41C, GENMASK(6, 4), (3 << 4)), -+ PIN_CFG(LPC1, SCU41C, GENMASK(6, 4), (4 << 4)), -+ PIN_CFG(SPIM1, SCU41C, GENMASK(6, 4), (5 << 4))); -+FUNCFG_DESCL(AB24, PIN_CFG(SGPM1, SCU41C, GENMASK(10, 8), (1 << 8)), -+ PIN_CFG(WDTRST7N, SCU41C, GENMASK(10, 8), (2 << 8)), -+ PIN_CFG(PESGWAKEN, SCU41C, GENMASK(10, 8), (3 << 8)), -+ PIN_CFG(SMON1, SCU41C, GENMASK(10, 8), (5 << 8))); -+FUNCFG_DESCL(W26, PIN_CFG(SGPM1, SCU41C, GENMASK(14, 12), (1 << 12)), -+ PIN_CFG(SMON1, SCU41C, GENMASK(14, 12), (5 << 12))); -+FUNCFG_DESCL(HOLE0); -+FUNCFG_DESCL(HOLE1); -+FUNCFG_DESCL(HOLE2); -+FUNCFG_DESCL(HOLE3); -+FUNCFG_DESCL(W25, PIN_CFG(HVI3C12, SCU420, GENMASK(2, 0), 1), -+ PIN_CFG(DI2C12, SCU420, GENMASK(2, 0), 2)); -+FUNCFG_DESCL(Y23, PIN_CFG(HVI3C12, SCU420, GENMASK(6, 4), (1 << 4)), -+ PIN_CFG(DI2C12, SCU420, GENMASK(6, 4), (2 << 4))); -+FUNCFG_DESCL(Y24, PIN_CFG(HVI3C13, SCU420, GENMASK(10, 8), (1 << 8)), -+ PIN_CFG(DI2C13, SCU420, GENMASK(10, 8), (2 << 8))); -+FUNCFG_DESCL(W21, PIN_CFG(HVI3C13, SCU420, GENMASK(14, 12), (1 << 12)), -+ PIN_CFG(DI2C13, SCU420, GENMASK(14, 12), (2 << 12))); -+FUNCFG_DESCL(AA23, PIN_CFG(HVI3C14, SCU420, GENMASK(18, 16), (1 << 16)), -+ PIN_CFG(DI2C14, SCU420, GENMASK(18, 16), (2 << 16))); -+FUNCFG_DESCL(AC22, PIN_CFG(HVI3C14, SCU420, GENMASK(22, 20), (1 << 20)), -+ PIN_CFG(DI2C14, SCU420, GENMASK(22, 20), (2 << 20))); -+FUNCFG_DESCL(AB22, PIN_CFG(HVI3C15, SCU420, GENMASK(26, 24), (1 << 24)), -+ PIN_CFG(DI2C15, SCU420, GENMASK(26, 24), (2 << 24))); -+FUNCFG_DESCL(Y21, PIN_CFG(HVI3C15, SCU420, GENMASK(30, 28), (1 << 28)), -+ PIN_CFG(DI2C15, SCU420, GENMASK(30, 28), (2 << 28))); -+FUNCFG_DESCL(AE20, PIN_CFG(I3C4, SCU424, GENMASK(2, 0), 1)); -+FUNCFG_DESCL(AF19, PIN_CFG(I3C4, SCU424, GENMASK(6, 4), (1 << 4))); -+FUNCFG_DESCL(Y22, PIN_CFG(I3C5, SCU424, GENMASK(10, 8), (1 << 8))); -+FUNCFG_DESCL(AA20, PIN_CFG(I3C5, SCU424, GENMASK(14, 12), (1 << 12))); -+FUNCFG_DESCL(AA22, PIN_CFG(I3C6, SCU424, GENMASK(18, 16), (1 << 16))); -+FUNCFG_DESCL(AB20, PIN_CFG(I3C6, SCU424, GENMASK(22, 20), (1 << 20))); -+FUNCFG_DESCL(AF18, PIN_CFG(I3C7, SCU424, GENMASK(26, 24), (1 << 24))); -+FUNCFG_DESCL(AE19, PIN_CFG(I3C7, SCU424, GENMASK(30, 28), (1 << 28))); -+FUNCFG_DESCL(AD20, PIN_CFG(I3C8, SCU428, GENMASK(2, 0), 1), -+ PIN_CFG(FSI0, SCU428, GENMASK(2, 0), 2)); -+FUNCFG_DESCL(AC20, PIN_CFG(I3C8, SCU428, GENMASK(6, 4), (1 << 4)), -+ PIN_CFG(FSI0, SCU428, GENMASK(6, 4), (2 << 4))); -+FUNCFG_DESCL(AA21, PIN_CFG(I3C9, SCU428, GENMASK(10, 8), (1 << 8)), -+ PIN_CFG(FSI1, SCU428, GENMASK(10, 8), (2 << 8))); -+FUNCFG_DESCL(AB21, PIN_CFG(I3C9, SCU428, GENMASK(14, 12), (1 << 12)), -+ PIN_CFG(FSI1, SCU428, GENMASK(14, 12), (2 << 12))); -+FUNCFG_DESCL(AC19, PIN_CFG(I3C10, SCU428, GENMASK(18, 16), (1 << 16)), -+ PIN_CFG(FSI2, SCU428, GENMASK(18, 16), (2 << 16))); -+FUNCFG_DESCL(AE18, PIN_CFG(I3C10, SCU428, GENMASK(22, 20), (1 << 20)), -+ PIN_CFG(FSI2, SCU428, GENMASK(22, 20), (2 << 20))); -+FUNCFG_DESCL(AD19, PIN_CFG(I3C11, SCU428, GENMASK(26, 24), (1 << 24)), -+ PIN_CFG(FSI3, SCU428, GENMASK(26, 24), (2 << 24))); -+FUNCFG_DESCL(AD18, PIN_CFG(I3C11, SCU428, GENMASK(30, 28), (1 << 28)), -+ PIN_CFG(FSI3, SCU428, GENMASK(30, 28), (2 << 28))); -+FUNCFG_DESCL(U25, PIN_CFG(HVI3C0, SCU42C, GENMASK(2, 0), 1), -+ PIN_CFG(DI2C8, SCU42C, GENMASK(2, 0), 2)); -+FUNCFG_DESCL(U26, PIN_CFG(HVI3C0, SCU42C, GENMASK(6, 4), (1 << 4)), -+ PIN_CFG(DI2C8, SCU42C, GENMASK(6, 4), (2 << 4))); -+FUNCFG_DESCL(Y26, PIN_CFG(HVI3C1, SCU42C, GENMASK(10, 8), (1 << 8)), -+ PIN_CFG(DI2C9, SCU42C, GENMASK(10, 8), (2 << 8))); -+FUNCFG_DESCL(AA24, PIN_CFG(HVI3C1, SCU42C, GENMASK(14, 12), (1 << 12)), -+ PIN_CFG(DI2C9, SCU42C, GENMASK(14, 12), (2 << 12))); -+FUNCFG_DESCL(R25, PIN_CFG(HVI3C2, SCU42C, GENMASK(18, 16), (1 << 16)), -+ PIN_CFG(DI2C10, SCU42C, GENMASK(18, 16), (2 << 16))); -+FUNCFG_DESCL(AA26, PIN_CFG(HVI3C2, SCU42C, GENMASK(22, 20), (1 << 20)), -+ PIN_CFG(DI2C10, SCU42C, GENMASK(22, 20), (2 << 20))); -+FUNCFG_DESCL(R26, PIN_CFG(HVI3C3, SCU42C, GENMASK(26, 24), (1 << 24)), -+ PIN_CFG(DI2C11, SCU42C, GENMASK(26, 24), (2 << 24))); -+FUNCFG_DESCL(Y25, PIN_CFG(HVI3C3, SCU42C, GENMASK(30, 28), (1 << 28)), -+ PIN_CFG(DI2C11, SCU42C, GENMASK(30, 28), (2 << 28))); -+FUNCFG_DESCL(B16, PIN_CFG(ESPI0, SCU430, GENMASK(2, 0), 1), -+ PIN_CFG(LPC0, SCU430, GENMASK(2, 0), 2)); -+FUNCFG_DESCL(D14, PIN_CFG(ESPI0, SCU430, GENMASK(6, 4), (1 << 4)), -+ PIN_CFG(LPC0, SCU430, GENMASK(6, 4), (2 << 4))); -+FUNCFG_DESCL(B15, PIN_CFG(ESPI0, SCU430, GENMASK(10, 8), (1 << 8)), -+ PIN_CFG(LPC0, SCU430, GENMASK(10, 8), (2 << 8))); -+FUNCFG_DESCL(B14, PIN_CFG(ESPI0, SCU430, GENMASK(14, 12), (1 << 12)), -+ PIN_CFG(LPC0, SCU430, GENMASK(14, 12), (2 << 12))); -+FUNCFG_DESCL(C17, PIN_CFG(ESPI0, SCU430, GENMASK(18, 16), (1 << 16)), -+ PIN_CFG(LPC0, SCU430, GENMASK(18, 16), (2 << 16)), -+ PIN_CFG(OSCCLK, SCU430, GENMASK(18, 16), (3 << 16))); -+FUNCFG_DESCL(B13, PIN_CFG(ESPI0, SCU430, GENMASK(22, 20), (1 << 20)), -+ PIN_CFG(LPC0, SCU430, GENMASK(22, 20), (2 << 20))); -+FUNCFG_DESCL(E14, PIN_CFG(ESPI0, SCU430, GENMASK(26, 24), (1 << 24)), -+ PIN_CFG(LPC0, SCU430, GENMASK(26, 24), (2 << 24))); -+FUNCFG_DESCL(C15, PIN_CFG(ESPI0, SCU430, GENMASK(30, 28), (1 << 28)), -+ PIN_CFG(LPC0, SCU430, GENMASK(30, 28), (2 << 28))); -+FUNCFG_DESCL(D24, PIN_CFG(SPI0, SCU434, GENMASK(2, 0), 1)); -+FUNCFG_DESCL(B23, PIN_CFG(SPI0, SCU434, GENMASK(6, 4), (1 << 4))); -+FUNCFG_DESCL(B22, PIN_CFG(SPI0, SCU434, GENMASK(10, 8), (1 << 8))); -+FUNCFG_DESCL(C23, PIN_CFG(QSPI0, SCU434, GENMASK(14, 12), (1 << 12))); -+FUNCFG_DESCL(B18, PIN_CFG(QSPI0, SCU434, GENMASK(18, 16), (1 << 16))); -+FUNCFG_DESCL(B21, PIN_CFG(SPI0CS1, SCU434, GENMASK(22, 20), (1 << 20))); -+FUNCFG_DESCL(M15, PIN_CFG(SPI0ABR, SCU434, GENMASK(26, 24), (1 << 24)), -+ PIN_CFG(TXD8, SCU434, GENMASK(26, 24), (3 << 24))); -+FUNCFG_DESCL(B19, PIN_CFG(SPI0WPN, SCU434, GENMASK(30, 28), (1 << 28)), -+ PIN_CFG(RXD8, SCU434, GENMASK(30, 28), (3 << 28))); -+FUNCFG_DESCL(B26, PIN_CFG(SPI1, SCU438, GENMASK(2, 0), 1), -+ PIN_CFG(TXD9, SCU438, GENMASK(2, 0), 3)); -+FUNCFG_DESCL(A25, PIN_CFG(SPI1, SCU438, GENMASK(6, 4), (1 << 4)), -+ PIN_CFG(RXD9, SCU438, GENMASK(6, 4), (3 << 4))); -+FUNCFG_DESCL(A24, PIN_CFG(SPI1, SCU438, GENMASK(10, 8), (1 << 8)), -+ PIN_CFG(TXD10, SCU438, GENMASK(10, 8), (3 << 8))); -+FUNCFG_DESCL(B24, PIN_CFG(QSPI1, SCU438, GENMASK(14, 12), (1 << 12)), -+ PIN_CFG(RXD10, SCU438, GENMASK(14, 12), (3 << 12))); -+FUNCFG_DESCL(E26, PIN_CFG(QSPI1, SCU438, GENMASK(18, 16), (1 << 16)), -+ PIN_CFG(TXD11, SCU438, GENMASK(18, 16), (3 << 16))); -+FUNCFG_DESCL(A21, PIN_CFG(SPI1CS1, SCU438, GENMASK(22, 20), (1 << 20)), -+ PIN_CFG(RXD11, SCU438, GENMASK(22, 20), (3 << 20))); -+FUNCFG_DESCL(A19, PIN_CFG(SPI1ABR, SCU438, GENMASK(26, 24), (1 << 24)), -+ PIN_CFG(THRU2, SCU438, GENMASK(26, 24), (4 << 24))); -+FUNCFG_DESCL(A18, PIN_CFG(SPI1WPN, SCU438, GENMASK(30, 28), (1 << 28)), -+ PIN_CFG(THRU2, SCU438, GENMASK(30, 28), (4 << 28))); -+FUNCFG_DESCL(D26, PIN_CFG(SPI2, SCU43C, GENMASK(2, 0), 1)); -+FUNCFG_DESCL(C26, PIN_CFG(SPI2, SCU43C, GENMASK(6, 4), (1 << 4))); -+FUNCFG_DESCL(A23, PIN_CFG(SPI2, SCU43C, GENMASK(10, 8), (1 << 8))); -+FUNCFG_DESCL(A22, PIN_CFG(SPI2, SCU43C, GENMASK(14, 12), (1 << 12))); -+FUNCFG_DESCL(B25, PIN_CFG(QSPI2, SCU43C, GENMASK(18, 16), (1 << 16)), -+ PIN_CFG(THRU3, SCU43C, GENMASK(18, 16), (4 << 16))); -+FUNCFG_DESCL(F26, PIN_CFG(QSPI2, SCU43C, GENMASK(22, 20), (1 << 20)), -+ PIN_CFG(THRU3, SCU43C, GENMASK(22, 20), (4 << 20))); -+FUNCFG_DESCL(A26, PIN_CFG(SPI2CS1, SCU43C, GENMASK(26, 24), (1 << 24))); -+FUNCFG_DESCL(A14, PIN_CFG(FWSPIABR, SCU43C, GENMASK(30, 28), (1 << 28))); -+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(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))); -+FUNCFG_DESCL(F13, PIN_CFG(JTAGM1, SCU440, GENMASK(26, 24), (1 << 24))); -+FUNCFG_DESCL(N15, PIN_CFG(FWSPIWPEN, SCU440, GENMASK(30, 28), (1 << 28))); -+FUNCFG_DESCL(C20, PIN_CFG(RGMII0, SCU444, GENMASK(2, 0), 1), -+ PIN_CFG(RMII0, SCU444, GENMASK(2, 0), 2)); -+FUNCFG_DESCL(C19, PIN_CFG(RGMII0, SCU444, GENMASK(6, 4), (1 << 4))); -+FUNCFG_DESCL(A8, PIN_CFG(RGMII0, SCU444, GENMASK(10, 8), (1 << 8)), -+ PIN_CFG(RMII0, SCU444, GENMASK(10, 8), (2 << 8))); -+FUNCFG_DESCL(R14, PIN_CFG(RGMII0, SCU444, GENMASK(14, 12), (1 << 12)), -+ PIN_CFG(RMII0, SCU444, GENMASK(14, 12), (2 << 12))); -+FUNCFG_DESCL(A7, PIN_CFG(RGMII0, SCU444, GENMASK(18, 16), (1 << 16)), -+ PIN_CFG(RMII0, SCU444, GENMASK(18, 16), (2 << 16))); -+FUNCFG_DESCL(P14, PIN_CFG(RGMII0, SCU444, GENMASK(22, 20), (1 << 20)), -+ PIN_CFG(RMII0, SCU444, GENMASK(22, 20), (2 << 20))); -+FUNCFG_DESCL(D20, PIN_CFG(RGMII0, SCU444, GENMASK(26, 24), (1 << 24)), -+ PIN_CFG(RMII0RCLKO, SCU444, GENMASK(26, 24), (2 << 24))); -+FUNCFG_DESCL(A6, PIN_CFG(RGMII0, SCU444, GENMASK(30, 28), (1 << 28)), -+ PIN_CFG(RMII0, SCU444, GENMASK(30, 28), (2 << 28))); -+FUNCFG_DESCL(B6, PIN_CFG(RGMII0, SCU448, GENMASK(2, 0), 1), -+ PIN_CFG(RMII0, SCU448, GENMASK(2, 0), 2)); -+FUNCFG_DESCL(N14, PIN_CFG(RGMII0, SCU448, GENMASK(6, 4), (1 << 4)), -+ PIN_CFG(RMII0, SCU448, GENMASK(6, 4), (2 << 4))); -+FUNCFG_DESCL(B7, PIN_CFG(RGMII0, SCU448, GENMASK(10, 8), (1 << 8))); -+FUNCFG_DESCL(B8, PIN_CFG(RGMII0, SCU448, GENMASK(14, 12), (1 << 12))); -+FUNCFG_DESCL(B9, PIN_CFG(MDIO0, SCU448, GENMASK(18, 16), (1 << 16))); -+FUNCFG_DESCL(M14, PIN_CFG(MDIO0, SCU448, GENMASK(22, 20), (1 << 20))); -+FUNCFG_DESCL(J11, PIN_CFG(VGA, SCU448, GENMASK(26, 24), (1 << 24))); -+FUNCFG_DESCL(E7, PIN_CFG(VGA, SCU448, GENMASK(30, 28), (1 << 28))); -+FUNCFG_DESCL(D19, PIN_CFG(RGMII1, SCU44C, GENMASK(2, 0), 1), -+ PIN_CFG(RMII1, SCU44C, GENMASK(2, 0), 2), -+ PIN_CFG(DSGPM0, SCU44C, GENMASK(2, 0), 4)); -+FUNCFG_DESCL(B11, PIN_CFG(RGMII1, SCU44C, GENMASK(6, 4), (1 << 4)), -+ PIN_CFG(SGPS, SCU44C, GENMASK(6, 4), (5 << 4))); -+FUNCFG_DESCL(D15, PIN_CFG(RGMII1, SCU44C, GENMASK(10, 8), (1 << 8)), -+ PIN_CFG(RMII1, SCU44C, GENMASK(10, 8), (2 << 8)), -+ PIN_CFG(TXD3, SCU44C, GENMASK(10, 8), (4 << 8))); -+FUNCFG_DESCL(B12, PIN_CFG(RGMII1, SCU44C, GENMASK(14, 12), (1 << 12)), -+ PIN_CFG(RMII1, SCU44C, GENMASK(14, 12), (2 << 12)), -+ PIN_CFG(RXD3, SCU44C, GENMASK(14, 12), (4 << 12))); -+FUNCFG_DESCL(B10, PIN_CFG(RGMII1, SCU44C, GENMASK(18, 16), (1 << 16)), -+ PIN_CFG(RMII1, SCU44C, GENMASK(18, 16), (2 << 16)), -+ PIN_CFG(DSGPM0, SCU44C, GENMASK(18, 16), (4 << 16))); -+FUNCFG_DESCL(P13, PIN_CFG(RGMII1, SCU44C, GENMASK(22, 20), (1 << 20)), -+ PIN_CFG(RMII1, SCU44C, GENMASK(22, 20), (2 << 20))); -+FUNCFG_DESCL(C18, PIN_CFG(RGMII1, SCU44C, GENMASK(26, 24), (1 << 24)), -+ PIN_CFG(RMII1RCLKO, SCU44C, GENMASK(26, 24), (2 << 24)), -+ PIN_CFG(SGPS, SCU44C, GENMASK(26, 24), (5 << 24))); -+FUNCFG_DESCL(C6, PIN_CFG(RGMII1, SCU44C, GENMASK(30, 28), (1 << 28)), -+ PIN_CFG(RMII1, SCU44C, GENMASK(30, 28), (2 << 28))); -+FUNCFG_DESCL(C7, PIN_CFG(RGMII1, SCU450, GENMASK(2, 0), 1), -+ PIN_CFG(RMII1, SCU450, GENMASK(2, 0), 2), -+ PIN_CFG(DSGPM0, SCU450, GENMASK(2, 0), 4)); -+FUNCFG_DESCL(D7, PIN_CFG(RGMII1, SCU450, GENMASK(6, 4), (1 << 4)), -+ PIN_CFG(RMII1, SCU450, GENMASK(6, 4), (2 << 4)), -+ PIN_CFG(DSGPM0, SCU450, GENMASK(6, 4), (4 << 4))); -+FUNCFG_DESCL(N13, PIN_CFG(RGMII1, SCU450, GENMASK(10, 8), (1 << 8)), -+ PIN_CFG(SGPS, SCU450, GENMASK(10, 8), (5 << 8))); -+FUNCFG_DESCL(C8, PIN_CFG(RGMII1, SCU450, GENMASK(14, 12), (1 << 12)), -+ PIN_CFG(SGPS, SCU450, GENMASK(14, 12), (5 << 12))); -+FUNCFG_DESCL(C9, PIN_CFG(MDIO1, SCU450, GENMASK(18, 16), (1 << 16))); -+FUNCFG_DESCL(C10, PIN_CFG(MDIO1, SCU450, GENMASK(22, 20), (1 << 20))); -+FUNCFG_DESCL(M16, PIN_CFG(FWQSPI, SCU450, GENMASK(26, 24), (1 << 24))); -+FUNCFG_DESCL(A15, PIN_CFG(FWQSPI, SCU450, GENMASK(30, 28), (1 << 28))); -+FUNCFG_DESCL(G11, PIN_CFG(I2C0, SCU454, GENMASK(2, 0), 1), -+ PIN_CFG(LTPI_PS_I2C0, SCU454, GENMASK(2, 0), 2)); -+FUNCFG_DESCL(H7, PIN_CFG(I2C0, SCU454, GENMASK(6, 4), (1 << 4)), -+ PIN_CFG(LTPI_PS_I2C0, SCU454, GENMASK(6, 4), (2 << 4))); -+FUNCFG_DESCL(H8, PIN_CFG(I2C1, SCU454, GENMASK(10, 8), (1 << 8)), -+ PIN_CFG(LTPI_PS_I2C1, SCU454, GENMASK(10, 8), (2 << 8))); -+FUNCFG_DESCL(H9, PIN_CFG(I2C1, SCU454, GENMASK(14, 12), (1 << 12)), -+ PIN_CFG(LTPI_PS_I2C1, SCU454, GENMASK(14, 12), (2 << 12))); -+FUNCFG_DESCL(H10, PIN_CFG(I2C2, SCU454, GENMASK(18, 16), (1 << 16)), -+ PIN_CFG(LTPI_PS_I2C2, SCU454, GENMASK(18, 16), (2 << 16))); -+FUNCFG_DESCL(H11, PIN_CFG(I2C2, SCU454, GENMASK(22, 20), (1 << 20)), -+ PIN_CFG(LTPI_PS_I2C2, SCU454, GENMASK(22, 20), (2 << 20))); -+FUNCFG_DESCL(J9, PIN_CFG(I2C3, SCU454, GENMASK(26, 24), (1 << 24)), -+ PIN_CFG(LTPI_PS_I2C3, SCU454, GENMASK(26, 24), (2 << 24))); -+FUNCFG_DESCL(J10, PIN_CFG(I2C3, SCU454, GENMASK(30, 28), (1 << 28)), -+ PIN_CFG(LTPI_PS_I2C3, SCU454, GENMASK(30, 28), (2 << 28))); -+FUNCFG_DESCL(E9, PIN_CFG(I2C4, SCU458, GENMASK(2, 0), 1), -+ PIN_CFG(I2CF1, SCU458, GENMASK(2, 0), 5)); -+FUNCFG_DESCL(F9, PIN_CFG(I2C4, SCU458, GENMASK(6, 4), (1 << 4)), -+ PIN_CFG(I2CF1, SCU458, GENMASK(6, 4), (5 << 4))); -+FUNCFG_DESCL(F8, PIN_CFG(I2C5, SCU458, GENMASK(10, 8), (1 << 8)), -+ PIN_CFG(I2CF1, SCU458, GENMASK(10, 8), (5 << 8))); -+FUNCFG_DESCL(M13, PIN_CFG(I2C5, SCU458, GENMASK(14, 12), (1 << 12)), -+ PIN_CFG(I2CF1, SCU458, GENMASK(14, 12), (5 << 12))); -+FUNCFG_DESCL(F7, PIN_CFG(I2C6, SCU458, GENMASK(18, 16), (1 << 16)), -+ PIN_CFG(I2CF2, SCU458, GENMASK(18, 16), (5 << 16))); -+FUNCFG_DESCL(D8, PIN_CFG(I2C6, SCU458, GENMASK(22, 20), (1 << 20)), -+ PIN_CFG(I2CF2, SCU458, GENMASK(22, 20), (5 << 20))); -+FUNCFG_DESCL(E8, PIN_CFG(I2C7, SCU458, GENMASK(26, 24), (1 << 24)), -+ PIN_CFG(I2CF2, SCU458, GENMASK(26, 24), (5 << 24))); -+FUNCFG_DESCL(L12, PIN_CFG(I2C7, SCU458, GENMASK(30, 28), (1 << 28)), -+ PIN_CFG(I2CF2, SCU458, GENMASK(30, 28), (5 << 28))); -+FUNCFG_DESCL(F12, PIN_CFG(I2C8, SCU45C, GENMASK(2, 0), 1), -+ PIN_CFG(I2CF0, SCU45C, GENMASK(2, 0), 5)); -+FUNCFG_DESCL(E12, PIN_CFG(I2C8, SCU45C, GENMASK(6, 4), (1 << 4)), -+ PIN_CFG(I2CF0, SCU45C, GENMASK(6, 4), (5 << 4))); -+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(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))); -+FUNCFG_DESCL(G9, PIN_CFG(I2C10, SCU45C, GENMASK(22, 20), (1 << 20)), -+ PIN_CFG(CANBUS, SCU45C, GENMASK(22, 20), (2 << 20))); -+FUNCFG_DESCL(G10, PIN_CFG(I2C11, SCU45C, GENMASK(26, 24), (1 << 24)), -+ PIN_CFG(USBUART, SCU45C, GENMASK(26, 24), (2 << 24))); -+FUNCFG_DESCL(K12, PIN_CFG(I2C11, SCU45C, GENMASK(30, 28), (1 << 28)), -+ PIN_CFG(USBUART, SCU45C, GENMASK(30, 28), (2 << 28))); -+FUNCFG_DESCL(W17, PIN_CFG(ADC0, SCU460, GENMASK(2, 0), 0), -+ PIN_CFG(GPIY0, SCU460, GENMASK(2, 0), 1), -+ PIN_CFG(SALT4, SCU460, GENMASK(2, 0), 2)); -+FUNCFG_DESCL(V18, PIN_CFG(ADC1, SCU460, GENMASK(6, 4), 0), -+ PIN_CFG(GPIY1, SCU460, GENMASK(6, 4), (1 << 4)), -+ PIN_CFG(SALT5, SCU460, GENMASK(6, 4), (2 << 4))); -+FUNCFG_DESCL(W18, PIN_CFG(ADC2, SCU460, GENMASK(10, 8), 0), -+ PIN_CFG(GPIY2, SCU460, GENMASK(10, 8), (1 << 8)), -+ PIN_CFG(SALT6, SCU460, GENMASK(10, 8), (2 << 8))); -+FUNCFG_DESCL(Y17, PIN_CFG(ADC3, SCU460, GENMASK(14, 12), 0), -+ PIN_CFG(GPIY3, SCU460, GENMASK(14, 12), (1 << 12)), -+ PIN_CFG(SALT7, SCU460, GENMASK(14, 12), (2 << 12))); -+FUNCFG_DESCL(AA18, PIN_CFG(ADC4, SCU460, GENMASK(18, 16), 0), -+ PIN_CFG(GPIY4, SCU460, GENMASK(18, 16), (1 << 16)), -+ PIN_CFG(SALT8, SCU460, GENMASK(18, 16), (2 << 16))); -+FUNCFG_DESCL(AA13, PIN_CFG(ADC5, SCU460, GENMASK(22, 20), 0), -+ PIN_CFG(GPIY5, SCU460, GENMASK(22, 20), (1 << 20)), -+ PIN_CFG(SALT9, SCU460, GENMASK(22, 20), (2 << 20))); -+FUNCFG_DESCL(Y18, PIN_CFG(ADC6, SCU460, GENMASK(26, 24), 0), -+ PIN_CFG(GPIY6, SCU460, GENMASK(26, 24), (1 << 24)), -+ PIN_CFG(SALT10, SCU460, GENMASK(26, 24), (2 << 24))); -+FUNCFG_DESCL(AA12, PIN_CFG(ADC7, SCU460, GENMASK(30, 28), 0), -+ PIN_CFG(GPIY7, SCU460, GENMASK(30, 28), (1 << 28)), -+ PIN_CFG(SALT11, SCU460, GENMASK(30, 28), (2 << 28))); -+FUNCFG_DESCL(W20, PIN_CFG(ADC8, SCU464, GENMASK(2, 0), 0), -+ PIN_CFG(GPIZ0, SCU464, GENMASK(2, 0), 1)); -+FUNCFG_DESCL(V20, PIN_CFG(ADC9, SCU464, GENMASK(6, 4), 0), -+ PIN_CFG(GPIZ1, SCU464, GENMASK(6, 4), (1 << 4))); -+FUNCFG_DESCL(Y11, PIN_CFG(ADC10, SCU464, GENMASK(10, 8), 0), -+ PIN_CFG(GPIZ2, SCU464, GENMASK(10, 8), (1 << 8))); -+FUNCFG_DESCL(V14, PIN_CFG(ADC11, SCU464, GENMASK(14, 12), 0), -+ PIN_CFG(GPIZ3, SCU464, GENMASK(14, 12), (1 << 12))); -+FUNCFG_DESCL(V19, PIN_CFG(ADC12, SCU464, GENMASK(18, 16), 0), -+ PIN_CFG(GPIZ4, SCU464, GENMASK(18, 16), (1 << 16))); -+FUNCFG_DESCL(W14, PIN_CFG(ADC13, SCU464, GENMASK(22, 20), 0), -+ PIN_CFG(GPIZ5, SCU464, GENMASK(22, 20), (1 << 20)), -+ PIN_CFG(AUXPWRGOOD0, SCU464, GENMASK(22, 20), (2 << 20))); -+FUNCFG_DESCL(Y20, PIN_CFG(ADC14, SCU464, GENMASK(26, 24), 0), -+ PIN_CFG(GPIZ6, SCU464, GENMASK(26, 24), (1 << 24)), -+ PIN_CFG(AUXPWRGOOD1, SCU464, GENMASK(26, 24), (2 << 24))); -+FUNCFG_DESCL(AB19, PIN_CFG(ADC15, SCU464, GENMASK(30, 28), 0), -+ PIN_CFG(GPIZ7, SCU464, GENMASK(30, 28), (1 << 28))); -+FUNCFG_DESCL(U21, PIN_CFG(SGPM0, SCU468, GENMASK(2, 0), 1), -+ PIN_CFG(SMON0, SCU468, GENMASK(2, 0), 2), -+ PIN_CFG(NCTS2, SCU468, GENMASK(2, 0), 3), -+ PIN_CFG(MACLINK0, SCU468, GENMASK(2, 0), 4)); -+FUNCFG_DESCL(T24, PIN_CFG(SGPM0, SCU468, GENMASK(6, 4), (1 << 4)), -+ PIN_CFG(SMON0, SCU468, GENMASK(6, 4), (2 << 4)), -+ PIN_CFG(NDCD2, SCU468, GENMASK(6, 4), (3 << 4)), -+ PIN_CFG(MACLINK2, SCU468, GENMASK(6, 4), (4 << 4))); -+FUNCFG_DESCL(V24, PIN_CFG(SGPM0LD_R, SCU468, GENMASK(10, 8), (2 << 8)), -+ PIN_CFG(HBLED, SCU468, GENMASK(10, 8), (2 << 8))); -+FUNCFG_DESCL(V22, PIN_CFG(SGPM0, SCU468, GENMASK(14, 12), (1 << 12)), -+ PIN_CFG(SMON0, SCU468, GENMASK(14, 12), (2 << 12)), -+ PIN_CFG(NDSR2, SCU468, GENMASK(14, 12), (3 << 12))); -+FUNCFG_DESCL(T23, PIN_CFG(SGPM0, SCU468, GENMASK(18, 16), (1 << 16)), -+ PIN_CFG(SMON0, SCU468, GENMASK(18, 16), (2 << 16)), -+ PIN_CFG(NRI2, SCU468, GENMASK(18, 16), (3 << 16))); -+FUNCFG_DESCL(AC25, PIN_CFG(SGPM1, SCU468, GENMASK(22, 20), (1 << 20)), -+ PIN_CFG(WDTRST4N, SCU468, GENMASK(22, 20), (2 << 20)), -+ PIN_CFG(NDTR2, SCU468, GENMASK(22, 20), (3 << 20)), -+ PIN_CFG(SMON1, SCU468, GENMASK(22, 20), (4 << 20))); -+FUNCFG_DESCL(AB25, PIN_CFG(SGPM1, SCU468, GENMASK(26, 24), (1 << 24)), -+ PIN_CFG(WDTRST5N, SCU468, GENMASK(26, 24), (2 << 24)), -+ PIN_CFG(NRTS2, SCU468, GENMASK(26, 24), (3 << 24)), -+ PIN_CFG(SMON1, SCU468, GENMASK(26, 24), (4 << 24))); -+FUNCFG_DESCL(AC24, PIN_CFG(SGPM1LD_R, SCU468, GENMASK(30, 28), (1 << 28)), -+ PIN_CFG(WDTRST6N, SCU468, GENMASK(30, 28), (2 << 28)), -+ PIN_CFG(MACLINK1, SCU468, GENMASK(30, 28), (3 << 28))); -+FUNCFG_DESCL(SGMII0, PIN_CFG(SGMII, SCU47C, BIT(0), 1 << 0)); -+FUNCFG_DESCL(PCIERC2_PERST, PIN_CFG(PE2SGRSTN, SCU908, BIT(1), 1 << 1)); -+FUNCFG_DESCL(PORTC_MODE, PIN_CFG(USB2CUD, SCU3B0, GENMASK(1, 0), 0), -+ PIN_CFG(USB2CD, SCU3B0, GENMASK(1, 0), 1 << 0), -+ PIN_CFG(USB2CH, SCU3B0, GENMASK(1, 0), 2 << 0), -+ PIN_CFG(USB2CU, SCU3B0, GENMASK(1, 0), 3 << 0)); -+FUNCFG_DESCL(PORTD_MODE, PIN_CFG(USB2DD, SCU3B0, GENMASK(3, 2), 1 << 2), -+ PIN_CFG(USB2DH, SCU3B0, GENMASK(3, 2), 2 << 2)); -+ -+static const struct aspeed_g7_pincfg pin_cfg[] = { -+ PINCFG_PIN(C16), PINCFG_PIN(C14), PINCFG_PIN(C11), -+ PINCFG_PIN(D9), PINCFG_PIN(F14), PINCFG_PIN(D10), -+ PINCFG_PIN(C12), PINCFG_PIN(C13), PINCFG_PIN(AC26), -+ PINCFG_PIN(AA25), PINCFG_PIN(AB23), PINCFG_PIN(U22), -+ PINCFG_PIN(V21), PINCFG_PIN(N26), PINCFG_PIN(P25), -+ PINCFG_PIN(N25), PINCFG_PIN(V23), PINCFG_PIN(W22), -+ PINCFG_PIN(AB26), PINCFG_PIN(AD26), PINCFG_PIN(P26), -+ PINCFG_PIN(AE26), PINCFG_PIN(AF26), PINCFG_PIN(AF25), -+ PINCFG_PIN(AE25), PINCFG_PIN(AD25), PINCFG_PIN(AF23), -+ PINCFG_PIN(AF20), PINCFG_PIN(AF21), PINCFG_PIN(AE21), -+ PINCFG_PIN(AE23), PINCFG_PIN(AD22), PINCFG_PIN(AF17), -+ PINCFG_PIN(AA16), PINCFG_PIN(Y16), PINCFG_PIN(V17), -+ PINCFG_PIN(J13), PINCFG_PIN(AB16), PINCFG_PIN(AC16), -+ PINCFG_PIN(AF16), PINCFG_PIN(AA15), PINCFG_PIN(AB15), -+ PINCFG_PIN(AC15), PINCFG_PIN(AD15), PINCFG_PIN(Y15), -+ PINCFG_PIN(AA14), PINCFG_PIN(W16), PINCFG_PIN(V16), -+ PINCFG_PIN(AB18), PINCFG_PIN(AC18), PINCFG_PIN(K13), -+ PINCFG_PIN(AA17), PINCFG_PIN(AB17), PINCFG_PIN(AD16), -+ PINCFG_PIN(AC17), PINCFG_PIN(AD17), PINCFG_PIN(AE16), -+ PINCFG_PIN(AE17), PINCFG_PIN(AB24), PINCFG_PIN(W26), -+ PINCFG_PIN(HOLE0), PINCFG_PIN(HOLE1), PINCFG_PIN(HOLE2), -+ PINCFG_PIN(HOLE3), PINCFG_PIN(W25), PINCFG_PIN(Y23), -+ PINCFG_PIN(Y24), PINCFG_PIN(W21), PINCFG_PIN(AA23), -+ PINCFG_PIN(AC22), PINCFG_PIN(AB22), PINCFG_PIN(Y21), -+ PINCFG_PIN(AE20), PINCFG_PIN(AF19), PINCFG_PIN(Y22), -+ PINCFG_PIN(AA20), PINCFG_PIN(AA22), PINCFG_PIN(AB20), -+ PINCFG_PIN(AF18), PINCFG_PIN(AE19), PINCFG_PIN(AD20), -+ PINCFG_PIN(AC20), PINCFG_PIN(AA21), PINCFG_PIN(AB21), -+ PINCFG_PIN(AC19), PINCFG_PIN(AE18), PINCFG_PIN(AD19), -+ PINCFG_PIN(AD18), PINCFG_PIN(U25), PINCFG_PIN(U26), -+ PINCFG_PIN(Y26), PINCFG_PIN(AA24), PINCFG_PIN(R25), -+ PINCFG_PIN(AA26), PINCFG_PIN(R26), PINCFG_PIN(Y25), -+ PINCFG_PIN(B16), PINCFG_PIN(D14), PINCFG_PIN(B15), -+ PINCFG_PIN(B14), PINCFG_PIN(C17), PINCFG_PIN(B13), -+ PINCFG_PIN(E14), PINCFG_PIN(C15), PINCFG_PIN(D24), -+ PINCFG_PIN(B23), PINCFG_PIN(B22), PINCFG_PIN(C23), -+ PINCFG_PIN(B18), PINCFG_PIN(B21), PINCFG_PIN(M15), -+ PINCFG_PIN(B19), PINCFG_PIN(B26), PINCFG_PIN(A25), -+ PINCFG_PIN(A24), PINCFG_PIN(B24), PINCFG_PIN(E26), -+ PINCFG_PIN(A21), PINCFG_PIN(A19), PINCFG_PIN(A18), -+ PINCFG_PIN(D26), PINCFG_PIN(C26), PINCFG_PIN(A23), -+ PINCFG_PIN(A22), PINCFG_PIN(B25), PINCFG_PIN(F26), -+ PINCFG_PIN(A26), PINCFG_PIN(A14), PINCFG_PIN(E10), -+ PINCFG_PIN(E13), PINCFG_PIN(D12), PINCFG_PIN(F10), -+ PINCFG_PIN(E11), PINCFG_PIN(F11), PINCFG_PIN(F13), -+ PINCFG_PIN(N15), PINCFG_PIN(C20), PINCFG_PIN(C19), -+ PINCFG_PIN(A8), PINCFG_PIN(R14), PINCFG_PIN(A7), -+ PINCFG_PIN(P14), PINCFG_PIN(D20), PINCFG_PIN(A6), -+ PINCFG_PIN(B6), PINCFG_PIN(N14), PINCFG_PIN(B7), -+ PINCFG_PIN(B8), PINCFG_PIN(B9), PINCFG_PIN(M14), -+ PINCFG_PIN(J11), PINCFG_PIN(E7), PINCFG_PIN(D19), -+ PINCFG_PIN(B11), PINCFG_PIN(D15), PINCFG_PIN(B12), -+ PINCFG_PIN(B10), PINCFG_PIN(P13), PINCFG_PIN(C18), -+ PINCFG_PIN(C6), PINCFG_PIN(C7), PINCFG_PIN(D7), -+ PINCFG_PIN(N13), PINCFG_PIN(C8), PINCFG_PIN(C9), -+ PINCFG_PIN(C10), PINCFG_PIN(M16), PINCFG_PIN(A15), -+ PINCFG_PIN(G11), PINCFG_PIN(H7), PINCFG_PIN(H8), -+ PINCFG_PIN(H9), PINCFG_PIN(H10), PINCFG_PIN(H11), -+ PINCFG_PIN(J9), PINCFG_PIN(J10), PINCFG_PIN(E9), -+ PINCFG_PIN(F9), PINCFG_PIN(F8), PINCFG_PIN(M13), -+ PINCFG_PIN(F7), PINCFG_PIN(D8), PINCFG_PIN(E8), -+ PINCFG_PIN(L12), PINCFG_PIN(F12), PINCFG_PIN(E12), -+ PINCFG_PIN(J12), PINCFG_PIN(G7), PINCFG_PIN(G8), -+ PINCFG_PIN(G9), PINCFG_PIN(G10), PINCFG_PIN(K12), -+ PINCFG_PIN(W17), PINCFG_PIN(V18), PINCFG_PIN(W18), -+ PINCFG_PIN(Y17), PINCFG_PIN(AA18), PINCFG_PIN(AA13), -+ PINCFG_PIN(Y18), PINCFG_PIN(AA12), PINCFG_PIN(W20), -+ PINCFG_PIN(V20), PINCFG_PIN(Y11), PINCFG_PIN(V14), -+ PINCFG_PIN(V19), PINCFG_PIN(W14), PINCFG_PIN(Y20), -+ PINCFG_PIN(AB19), PINCFG_PIN(U21), PINCFG_PIN(T24), -+ PINCFG_PIN(V24), PINCFG_PIN(V22), PINCFG_PIN(T23), -+ PINCFG_PIN(AC25), PINCFG_PIN(AB25), PINCFG_PIN(AC24), -+ PINCFG_PIN(SGMII0), PINCFG_PIN(PCIERC2_PERST), -+ PINCFG_PIN(PORTC_MODE), PINCFG_PIN(PORTD_MODE), -+}; -+ -+static int aspeed_g7_soc1_dt_node_to_map(struct pinctrl_dev *pctldev, -+ struct device_node *np_config, -+ struct pinctrl_map **map, u32 *num_maps) -+{ -+ return pinconf_generic_dt_node_to_map(pctldev, np_config, map, num_maps, -+ PIN_MAP_TYPE_INVALID); -+} -+ -+static void aspeed_g7_soc1_dt_free_map(struct pinctrl_dev *pctldev, -+ struct pinctrl_map *map, u32 num_maps) -+{ -+ kfree(map); -+} -+ -+static const struct pinctrl_ops aspeed_g7_soc1_pinctrl_ops = { -+ .get_groups_count = aspeed_pinctrl_get_groups_count, -+ .get_group_name = aspeed_pinctrl_get_group_name, -+ .get_group_pins = aspeed_pinctrl_get_group_pins, -+ .pin_dbg_show = aspeed_pinctrl_pin_dbg_show, -+ .dt_node_to_map = aspeed_g7_soc1_dt_node_to_map, -+ .dt_free_map = aspeed_g7_soc1_dt_free_map, -+}; -+ -+static const struct pinmux_ops aspeed_g7_soc1_pinmux_ops = { -+ .get_functions_count = aspeed_pinmux_get_fn_count, -+ .get_function_name = aspeed_pinmux_get_fn_name, -+ .get_function_groups = aspeed_pinmux_get_fn_groups, -+ .set_mux = aspeed_g7_pinmux_set_mux, -+ .gpio_request_enable = aspeed_g7_gpio_request_enable, -+ .strict = true, -+}; -+ -+static const struct pinconf_ops aspeed_g7_soc1_pinconf_ops = { -+ .is_generic = true, -+ .pin_config_get = aspeed_pin_config_get, -+ .pin_config_set = aspeed_pin_config_set, -+ .pin_config_group_get = aspeed_pin_config_group_get, -+ .pin_config_group_set = aspeed_pin_config_group_set, -+}; -+ -+/* pinctrl_desc */ -+static struct pinctrl_desc aspeed_g7_soc1_pinctrl_desc = { -+ .name = "aspeed-g7-soc1-pinctrl", -+ .pins = aspeed_g7_soc1_pins, -+ .npins = ARRAY_SIZE(aspeed_g7_soc1_pins), -+ .pctlops = &aspeed_g7_soc1_pinctrl_ops, -+ .pmxops = &aspeed_g7_soc1_pinmux_ops, -+ .confops = &aspeed_g7_soc1_pinconf_ops, -+ .owner = THIS_MODULE, -+}; -+ -+static struct aspeed_pin_config aspeed_g7_configs[] = { -+ /* GPIOA */ -+ { PIN_CONFIG_DRIVE_STRENGTH, { C16, C16 }, SCU4C0, GENMASK(1, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { C14, C14 }, SCU4C0, GENMASK(3, 2) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { C11, C11 }, SCU4C0, GENMASK(5, 4) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { D9, D9 }, SCU4C0, GENMASK(7, 6) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { F14, F14 }, SCU4C0, GENMASK(9, 8) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { D10, D10 }, SCU4C0, GENMASK(11, 10) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { C12, C12 }, SCU4C0, GENMASK(13, 12) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { C13, C13 }, SCU4C0, GENMASK(15, 14) }, -+ { PIN_CONFIG_POWER_SOURCE, { C16, C13 }, SCU4A0, BIT_MASK(4) }, -+ /* GPIOI */ -+ { PIN_CONFIG_DRIVE_STRENGTH, { W25, W25 }, SCU4C0, GENMASK(17, 16) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { Y23, Y23 }, SCU4C0, GENMASK(19, 18) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { Y24, Y24 }, SCU4C0, GENMASK(21, 20) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { W21, W21 }, SCU4C0, GENMASK(23, 22) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AA23, AA23 }, SCU4C0, GENMASK(25, 24) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AC22, AC22 }, SCU4C0, GENMASK(27, 26) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AB22, AB22 }, SCU4C0, GENMASK(29, 28) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { Y21, Y21 }, SCU4C0, GENMASK(31, 30) }, -+ { PIN_CONFIG_POWER_SOURCE, { W25, Y21 }, SCU4A0, BIT_MASK(12) }, -+ /* GPIOJ */ -+ { PIN_CONFIG_DRIVE_STRENGTH, { AE20, AE20 }, SCU4C4, GENMASK(1, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AF19, AF19 }, SCU4C4, GENMASK(3, 2) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { Y22, Y22 }, SCU4C4, GENMASK(5, 4) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AA20, AA20 }, SCU4C4, GENMASK(7, 6) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AA22, AA22 }, SCU4C4, GENMASK(9, 8) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AB20, AB20 }, SCU4C4, GENMASK(11, 10) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AF18, AF18 }, SCU4C4, GENMASK(13, 12) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AE19, AE19 }, SCU4C4, GENMASK(15, 14) }, -+ /* GPIOK */ -+ { PIN_CONFIG_DRIVE_STRENGTH, { AD20, AD20 }, SCU4C4, GENMASK(17, 16) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AC20, AC20 }, SCU4C4, GENMASK(19, 18) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AA21, AA21 }, SCU4C4, GENMASK(21, 20) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AB21, AB21 }, SCU4C4, GENMASK(23, 22) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AC19, AC19 }, SCU4C4, GENMASK(25, 24) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AE18, AE18 }, SCU4C4, GENMASK(27, 26) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AD19, AD19 }, SCU4C4, GENMASK(29, 28) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AD18, AD18 }, SCU4C4, GENMASK(31, 30) }, -+ /* GPIOL */ -+ { PIN_CONFIG_DRIVE_STRENGTH, { U25, U25 }, SCU4C8, GENMASK(1, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { U26, U26 }, SCU4C8, GENMASK(3, 2) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { Y26, Y26 }, SCU4C8, GENMASK(5, 4) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AA24, AA24 }, SCU4C8, GENMASK(7, 6) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { R25, R25 }, SCU4C8, GENMASK(9, 8) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { AA26, AA26 }, SCU4C8, GENMASK(11, 10) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { R26, R26 }, SCU4C8, GENMASK(13, 12) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { Y25, Y25 }, SCU4C8, GENMASK(15, 14) }, -+ { PIN_CONFIG_POWER_SOURCE, { U25, Y25 }, SCU4A0, BIT_MASK(15) }, -+ /* GPIOM */ -+ { PIN_CONFIG_DRIVE_STRENGTH, { B16, B16 }, SCU4C8, GENMASK(17, 16) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { D14, D14 }, SCU4C8, GENMASK(19, 18) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { B15, B15 }, SCU4C8, GENMASK(21, 20) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { B14, B14 }, SCU4C8, GENMASK(23, 22) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { C17, C17 }, SCU4C8, GENMASK(25, 24) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { B13, B13 }, SCU4C8, GENMASK(27, 26) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { E14, E14 }, SCU4C8, GENMASK(29, 28) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { C15, C15 }, SCU4C8, GENMASK(31, 30) }, -+ { PIN_CONFIG_POWER_SOURCE, { B16, C15 }, SCU4A0, BIT_MASK(16) }, -+ /* GPION */ -+ { PIN_CONFIG_DRIVE_STRENGTH, { D24, D24 }, SCU4CC, GENMASK(1, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { B23, B23 }, SCU4CC, GENMASK(3, 2) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { B22, B22 }, SCU4CC, GENMASK(5, 4) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { C23, C23 }, SCU4CC, GENMASK(7, 6) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { B18, B18 }, SCU4CC, GENMASK(9, 8) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { B21, B21 }, SCU4CC, GENMASK(11, 10) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { M15, M15 }, SCU4CC, GENMASK(13, 12) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { B19, B19 }, SCU4CC, GENMASK(15, 14) }, -+ { PIN_CONFIG_POWER_SOURCE, { D24, B19 }, SCU4A0, BIT_MASK(17) }, -+ /* GPIOO */ -+ { PIN_CONFIG_DRIVE_STRENGTH, { B26, B26 }, SCU4CC, GENMASK(17, 16) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { A25, A25 }, SCU4CC, GENMASK(19, 18) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { A24, A24 }, SCU4CC, GENMASK(21, 20) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { B24, B24 }, SCU4CC, GENMASK(23, 22) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { E26, E26 }, SCU4CC, GENMASK(25, 24) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { A21, A21 }, SCU4CC, GENMASK(27, 26) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { A19, A19 }, SCU4CC, GENMASK(29, 28) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { A18, A18 }, SCU4CC, GENMASK(31, 30) }, -+ { PIN_CONFIG_POWER_SOURCE, { B26, A18 }, SCU4A0, BIT_MASK(18) }, -+ /* GPIOP */ -+ { PIN_CONFIG_DRIVE_STRENGTH, { D26, D26 }, SCU4D0, GENMASK(1, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { C26, C26 }, SCU4D0, GENMASK(3, 2) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { A23, A23 }, SCU4D0, GENMASK(5, 4) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { A22, A22 }, SCU4D0, GENMASK(7, 6) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { B25, B25 }, SCU4D0, GENMASK(9, 8) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { F26, F26 }, SCU4D0, GENMASK(11, 10) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { A26, A26 }, SCU4D0, GENMASK(13, 12) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { A14, A14 }, SCU4D0, GENMASK(15, 14) }, -+ { PIN_CONFIG_POWER_SOURCE, { D26, A14 }, SCU4A0, BIT_MASK(19) }, -+ /* GPIOQ */ -+ { PIN_CONFIG_DRIVE_STRENGTH, { E10, E10 }, SCU4D0, GENMASK(17, 16) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { E13, E13 }, SCU4D0, GENMASK(19, 18) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { D12, D12 }, SCU4D0, GENMASK(21, 20) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { F10, F10 }, SCU4D0, GENMASK(23, 22) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { E11, E11 }, SCU4D0, GENMASK(25, 24) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { F11, F11 }, SCU4D0, GENMASK(27, 26) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { F13, F13 }, SCU4D0, GENMASK(29, 28) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { N15, N15 }, SCU4D0, GENMASK(31, 30) }, -+ /* GPIOR */ -+ { PIN_CONFIG_DRIVE_STRENGTH, { C20, C20 }, SCU4D4, GENMASK(1, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { C19, C19 }, SCU4D4, GENMASK(3, 2) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { A8, A8 }, SCU4D4, GENMASK(5, 4) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { R14, R14 }, SCU4D4, GENMASK(7, 6) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { A7, A7 }, SCU4D4, GENMASK(9, 8) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { P14, P14 }, SCU4D4, GENMASK(11, 10) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { D20, D20 }, SCU4D4, GENMASK(13, 12) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { A6, A6 }, SCU4D4, GENMASK(15, 14) }, -+ { PIN_CONFIG_POWER_SOURCE, { C20, A6 }, SCU4A0, BIT_MASK(21) }, -+ /* GPIOS */ -+ { PIN_CONFIG_DRIVE_STRENGTH, { B6, B6 }, SCU4D4, GENMASK(17, 16) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { N14, N14 }, SCU4D4, GENMASK(19, 18) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { B7, B7 }, SCU4D4, GENMASK(21, 20) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { B8, B8 }, SCU4D4, GENMASK(23, 22) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { B9, B9 }, SCU4D4, GENMASK(25, 24) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { M14, M14 }, SCU4D4, GENMASK(27, 26) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { J11, J11 }, SCU4D4, GENMASK(29, 28) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { E7, E7 }, SCU4D4, GENMASK(31, 30) }, -+ { PIN_CONFIG_POWER_SOURCE, { B6, E7 }, SCU4A0, BIT_MASK(22) }, -+ /* GPIOT */ -+ { PIN_CONFIG_DRIVE_STRENGTH, { D19, D19 }, SCU4D8, GENMASK(1, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { B11, B11 }, SCU4D8, GENMASK(3, 2) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { D15, D15 }, SCU4D8, GENMASK(5, 4) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { B12, B12 }, SCU4D8, GENMASK(7, 6) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { B10, B10 }, SCU4D8, GENMASK(9, 8) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { P13, P13 }, SCU4D8, GENMASK(11, 10) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { C18, C18 }, SCU4D8, GENMASK(13, 12) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { C6, C6 }, SCU4D8, GENMASK(15, 14) }, -+ { PIN_CONFIG_POWER_SOURCE, { D19, C6 }, SCU4A0, BIT_MASK(23) }, -+ /* GPIOU */ -+ { PIN_CONFIG_DRIVE_STRENGTH, { C7, C7 }, SCU4D8, GENMASK(17, 16) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { D7, D7 }, SCU4D8, GENMASK(19, 18) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { N13, N13 }, SCU4D8, GENMASK(21, 20) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { C8, C8 }, SCU4D8, GENMASK(23, 22) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { C9, C9 }, SCU4D8, GENMASK(25, 24) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { C10, C10 }, SCU4D8, GENMASK(27, 26) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { M16, M16 }, SCU4D8, GENMASK(29, 28) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { A15, A15 }, SCU4D8, GENMASK(31, 30) }, -+ { PIN_CONFIG_POWER_SOURCE, { C7, A15 }, SCU4A0, BIT_MASK(24) }, -+ /* GPIOW */ -+ { PIN_CONFIG_DRIVE_STRENGTH, { E9, E9 }, SCU4DC, GENMASK(1, 0) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { F9, F9 }, SCU4DC, GENMASK(3, 2) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { F8, F8 }, SCU4DC, GENMASK(5, 4) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { M13, M13 }, SCU4DC, GENMASK(7, 6) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { F7, F7 }, SCU4DC, GENMASK(9, 8) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { D8, D8 }, SCU4DC, GENMASK(11, 10) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { E8, E8 }, SCU4DC, GENMASK(13, 12) }, -+ { PIN_CONFIG_DRIVE_STRENGTH, { L12, L12 }, SCU4DC, GENMASK(15, 14) }, -+ { PIN_CONFIG_POWER_SOURCE, { E9, L12 }, SCU4A0, BIT_MASK(26) }, -+ -+ ASPEED_PULL_DOWN_PINCONF(C16, SCU480, 0), -+ ASPEED_PULL_DOWN_PINCONF(C14, SCU480, 1), -+ ASPEED_PULL_DOWN_PINCONF(C11, SCU480, 2), -+ ASPEED_PULL_DOWN_PINCONF(D9, SCU480, 3), -+ ASPEED_PULL_DOWN_PINCONF(F14, SCU480, 4), -+ ASPEED_PULL_DOWN_PINCONF(D10, SCU480, 5), -+ ASPEED_PULL_DOWN_PINCONF(C12, SCU480, 6), -+ ASPEED_PULL_DOWN_PINCONF(C13, SCU480, 7), -+ ASPEED_PULL_DOWN_PINCONF(AC26, SCU480, 8), -+ ASPEED_PULL_DOWN_PINCONF(AA25, SCU480, 9), -+ ASPEED_PULL_DOWN_PINCONF(AB23, SCU480, 10), -+ ASPEED_PULL_DOWN_PINCONF(U22, SCU480, 11), -+ ASPEED_PULL_DOWN_PINCONF(V21, SCU480, 12), -+ ASPEED_PULL_DOWN_PINCONF(N26, SCU480, 13), -+ ASPEED_PULL_DOWN_PINCONF(P25, SCU480, 14), -+ ASPEED_PULL_DOWN_PINCONF(N25, SCU480, 15), -+ ASPEED_PULL_DOWN_PINCONF(V23, SCU480, 16), -+ ASPEED_PULL_DOWN_PINCONF(W22, SCU480, 17), -+ ASPEED_PULL_DOWN_PINCONF(AB26, SCU480, 18), -+ ASPEED_PULL_DOWN_PINCONF(AD26, SCU480, 19), -+ ASPEED_PULL_DOWN_PINCONF(P26, SCU480, 20), -+ ASPEED_PULL_DOWN_PINCONF(AE26, SCU480, 21), -+ ASPEED_PULL_DOWN_PINCONF(AF26, SCU480, 22), -+ ASPEED_PULL_DOWN_PINCONF(AF25, SCU480, 23), -+ ASPEED_PULL_DOWN_PINCONF(AE25, SCU480, 24), -+ ASPEED_PULL_DOWN_PINCONF(AD25, SCU480, 25), -+ ASPEED_PULL_DOWN_PINCONF(AF23, SCU480, 26), -+ ASPEED_PULL_DOWN_PINCONF(AF20, SCU480, 27), -+ ASPEED_PULL_DOWN_PINCONF(AF21, SCU480, 28), -+ ASPEED_PULL_DOWN_PINCONF(AE21, SCU480, 29), -+ ASPEED_PULL_DOWN_PINCONF(AE23, SCU480, 30), -+ ASPEED_PULL_DOWN_PINCONF(AD22, SCU480, 31), -+ ASPEED_PULL_DOWN_PINCONF(AF17, SCU484, 0), -+ ASPEED_PULL_DOWN_PINCONF(AA16, SCU484, 1), -+ ASPEED_PULL_DOWN_PINCONF(Y16, SCU484, 2), -+ ASPEED_PULL_DOWN_PINCONF(V17, SCU484, 3), -+ ASPEED_PULL_DOWN_PINCONF(J13, SCU484, 4), -+ ASPEED_PULL_DOWN_PINCONF(AB16, SCU484, 5), -+ ASPEED_PULL_DOWN_PINCONF(AC16, SCU484, 6), -+ ASPEED_PULL_DOWN_PINCONF(AF16, SCU484, 7), -+ ASPEED_PULL_DOWN_PINCONF(AA15, SCU484, 8), -+ ASPEED_PULL_DOWN_PINCONF(AB15, SCU484, 9), -+ ASPEED_PULL_DOWN_PINCONF(AC15, SCU484, 10), -+ ASPEED_PULL_DOWN_PINCONF(AD15, SCU484, 11), -+ ASPEED_PULL_DOWN_PINCONF(Y15, SCU484, 12), -+ ASPEED_PULL_DOWN_PINCONF(AA14, SCU484, 13), -+ ASPEED_PULL_DOWN_PINCONF(W16, SCU484, 14), -+ ASPEED_PULL_DOWN_PINCONF(V16, SCU484, 15), -+ ASPEED_PULL_DOWN_PINCONF(AB18, SCU484, 16), -+ ASPEED_PULL_DOWN_PINCONF(AC18, SCU484, 17), -+ ASPEED_PULL_DOWN_PINCONF(K13, SCU484, 18), -+ ASPEED_PULL_DOWN_PINCONF(AA17, SCU484, 19), -+ ASPEED_PULL_DOWN_PINCONF(AB17, SCU484, 20), -+ ASPEED_PULL_DOWN_PINCONF(AD16, SCU484, 21), -+ ASPEED_PULL_DOWN_PINCONF(AC17, SCU484, 22), -+ ASPEED_PULL_DOWN_PINCONF(AD17, SCU484, 23), -+ ASPEED_PULL_DOWN_PINCONF(AE16, SCU484, 24), -+ ASPEED_PULL_DOWN_PINCONF(AE17, SCU484, 25), -+ ASPEED_PULL_DOWN_PINCONF(AB24, SCU484, 26), -+ ASPEED_PULL_DOWN_PINCONF(W26, SCU484, 27), -+ ASPEED_PULL_DOWN_PINCONF(HOLE0, SCU484, 28), -+ ASPEED_PULL_DOWN_PINCONF(HOLE1, SCU484, 29), -+ ASPEED_PULL_DOWN_PINCONF(HOLE2, SCU484, 30), -+ ASPEED_PULL_DOWN_PINCONF(HOLE3, SCU484, 31), -+ ASPEED_PULL_DOWN_PINCONF(W25, SCU488, 0), -+ ASPEED_PULL_DOWN_PINCONF(Y23, SCU488, 1), -+ ASPEED_PULL_DOWN_PINCONF(Y24, SCU488, 2), -+ ASPEED_PULL_DOWN_PINCONF(W21, SCU488, 3), -+ ASPEED_PULL_DOWN_PINCONF(AA23, SCU488, 4), -+ ASPEED_PULL_DOWN_PINCONF(AC22, SCU488, 5), -+ ASPEED_PULL_DOWN_PINCONF(AB22, SCU488, 6), -+ ASPEED_PULL_DOWN_PINCONF(Y21, SCU488, 7), -+ ASPEED_PULL_DOWN_PINCONF(AE20, SCU488, 8), -+ ASPEED_PULL_DOWN_PINCONF(AF19, SCU488, 9), -+ ASPEED_PULL_DOWN_PINCONF(Y22, SCU488, 10), -+ ASPEED_PULL_DOWN_PINCONF(AA20, SCU488, 11), -+ ASPEED_PULL_DOWN_PINCONF(AA22, SCU488, 12), -+ ASPEED_PULL_DOWN_PINCONF(AB20, SCU488, 13), -+ ASPEED_PULL_DOWN_PINCONF(AF18, SCU488, 14), -+ ASPEED_PULL_DOWN_PINCONF(AE19, SCU488, 15), -+ ASPEED_PULL_DOWN_PINCONF(AD20, SCU488, 16), -+ ASPEED_PULL_DOWN_PINCONF(AC20, SCU488, 17), -+ ASPEED_PULL_DOWN_PINCONF(AA21, SCU488, 18), -+ ASPEED_PULL_DOWN_PINCONF(AB21, SCU488, 19), -+ ASPEED_PULL_DOWN_PINCONF(AC19, SCU488, 20), -+ ASPEED_PULL_DOWN_PINCONF(AE18, SCU488, 21), -+ ASPEED_PULL_DOWN_PINCONF(AD19, SCU488, 22), -+ ASPEED_PULL_DOWN_PINCONF(AD18, SCU488, 23), -+ ASPEED_PULL_DOWN_PINCONF(U25, SCU488, 24), -+ ASPEED_PULL_DOWN_PINCONF(U26, SCU488, 25), -+ ASPEED_PULL_DOWN_PINCONF(Y26, SCU488, 26), -+ ASPEED_PULL_DOWN_PINCONF(AA24, SCU488, 27), -+ ASPEED_PULL_DOWN_PINCONF(R25, SCU488, 28), -+ ASPEED_PULL_DOWN_PINCONF(AA26, SCU488, 29), -+ ASPEED_PULL_DOWN_PINCONF(R26, SCU488, 30), -+ ASPEED_PULL_DOWN_PINCONF(Y25, SCU488, 31), -+ ASPEED_PULL_DOWN_PINCONF(B16, SCU48C, 0), -+ ASPEED_PULL_DOWN_PINCONF(D14, SCU48C, 1), -+ ASPEED_PULL_DOWN_PINCONF(B15, SCU48C, 2), -+ ASPEED_PULL_DOWN_PINCONF(B14, SCU48C, 3), -+ ASPEED_PULL_DOWN_PINCONF(C17, SCU48C, 4), -+ ASPEED_PULL_DOWN_PINCONF(B13, SCU48C, 5), -+ ASPEED_PULL_DOWN_PINCONF(E14, SCU48C, 6), -+ ASPEED_PULL_DOWN_PINCONF(C15, SCU48C, 7), -+ ASPEED_PULL_DOWN_PINCONF(D24, SCU48C, 8), -+ ASPEED_PULL_DOWN_PINCONF(B23, SCU48C, 9), -+ ASPEED_PULL_DOWN_PINCONF(B22, SCU48C, 10), -+ ASPEED_PULL_DOWN_PINCONF(C23, SCU48C, 11), -+ ASPEED_PULL_DOWN_PINCONF(B18, SCU48C, 12), -+ ASPEED_PULL_DOWN_PINCONF(B21, SCU48C, 13), -+ ASPEED_PULL_DOWN_PINCONF(M15, SCU48C, 14), -+ ASPEED_PULL_DOWN_PINCONF(B19, SCU48C, 15), -+ ASPEED_PULL_DOWN_PINCONF(B26, SCU48C, 16), -+ ASPEED_PULL_DOWN_PINCONF(A25, SCU48C, 17), -+ ASPEED_PULL_DOWN_PINCONF(A24, SCU48C, 18), -+ ASPEED_PULL_DOWN_PINCONF(B24, SCU48C, 19), -+ ASPEED_PULL_DOWN_PINCONF(E26, SCU48C, 20), -+ ASPEED_PULL_DOWN_PINCONF(A21, SCU48C, 21), -+ ASPEED_PULL_DOWN_PINCONF(A19, SCU48C, 22), -+ ASPEED_PULL_DOWN_PINCONF(A18, SCU48C, 23), -+ ASPEED_PULL_DOWN_PINCONF(D26, SCU48C, 24), -+ ASPEED_PULL_DOWN_PINCONF(C26, SCU48C, 25), -+ ASPEED_PULL_DOWN_PINCONF(A23, SCU48C, 26), -+ ASPEED_PULL_DOWN_PINCONF(A22, SCU48C, 27), -+ ASPEED_PULL_DOWN_PINCONF(B25, SCU48C, 28), -+ ASPEED_PULL_DOWN_PINCONF(F26, SCU48C, 29), -+ ASPEED_PULL_DOWN_PINCONF(A26, SCU48C, 30), -+ ASPEED_PULL_DOWN_PINCONF(A14, SCU48C, 31), -+ ASPEED_PULL_DOWN_PINCONF(E10, SCU490, 0), -+ ASPEED_PULL_DOWN_PINCONF(E13, SCU490, 1), -+ ASPEED_PULL_DOWN_PINCONF(D12, SCU490, 2), -+ ASPEED_PULL_DOWN_PINCONF(F10, SCU490, 3), -+ ASPEED_PULL_DOWN_PINCONF(E11, SCU490, 4), -+ ASPEED_PULL_DOWN_PINCONF(F11, SCU490, 5), -+ ASPEED_PULL_DOWN_PINCONF(F13, SCU490, 6), -+ ASPEED_PULL_DOWN_PINCONF(N15, SCU490, 7), -+ ASPEED_PULL_DOWN_PINCONF(C20, SCU490, 8), -+ ASPEED_PULL_DOWN_PINCONF(C19, SCU490, 9), -+ ASPEED_PULL_DOWN_PINCONF(A8, SCU490, 10), -+ ASPEED_PULL_DOWN_PINCONF(R14, SCU490, 11), -+ ASPEED_PULL_DOWN_PINCONF(A7, SCU490, 12), -+ ASPEED_PULL_DOWN_PINCONF(P14, SCU490, 13), -+ ASPEED_PULL_DOWN_PINCONF(D20, SCU490, 14), -+ ASPEED_PULL_DOWN_PINCONF(A6, SCU490, 15), -+ ASPEED_PULL_DOWN_PINCONF(B6, SCU490, 16), -+ ASPEED_PULL_DOWN_PINCONF(N14, SCU490, 17), -+ ASPEED_PULL_DOWN_PINCONF(B7, SCU490, 18), -+ ASPEED_PULL_DOWN_PINCONF(B8, SCU490, 19), -+ ASPEED_PULL_DOWN_PINCONF(B9, SCU490, 20), -+ ASPEED_PULL_DOWN_PINCONF(M14, SCU490, 21), -+ ASPEED_PULL_DOWN_PINCONF(J11, SCU490, 22), -+ ASPEED_PULL_DOWN_PINCONF(E7, SCU490, 23), -+ ASPEED_PULL_DOWN_PINCONF(D19, SCU490, 24), -+ ASPEED_PULL_DOWN_PINCONF(B11, SCU490, 25), -+ ASPEED_PULL_DOWN_PINCONF(D15, SCU490, 26), -+ ASPEED_PULL_DOWN_PINCONF(B12, SCU490, 27), -+ ASPEED_PULL_DOWN_PINCONF(B10, SCU490, 28), -+ ASPEED_PULL_DOWN_PINCONF(P13, SCU490, 29), -+ ASPEED_PULL_DOWN_PINCONF(C18, SCU490, 30), -+ ASPEED_PULL_DOWN_PINCONF(C6, SCU490, 31), -+ ASPEED_PULL_DOWN_PINCONF(C7, SCU494, 0), -+ ASPEED_PULL_DOWN_PINCONF(D7, SCU494, 1), -+ ASPEED_PULL_DOWN_PINCONF(N13, SCU494, 2), -+ ASPEED_PULL_DOWN_PINCONF(C8, SCU494, 3), -+ ASPEED_PULL_DOWN_PINCONF(C9, SCU494, 4), -+ ASPEED_PULL_DOWN_PINCONF(C10, SCU494, 5), -+ ASPEED_PULL_DOWN_PINCONF(M16, SCU494, 6), -+ ASPEED_PULL_DOWN_PINCONF(A15, SCU494, 7), -+ ASPEED_PULL_DOWN_PINCONF(G11, SCU494, 8), -+ ASPEED_PULL_DOWN_PINCONF(H7, SCU494, 9), -+ ASPEED_PULL_DOWN_PINCONF(H8, SCU494, 10), -+ ASPEED_PULL_DOWN_PINCONF(H9, SCU494, 11), -+ ASPEED_PULL_DOWN_PINCONF(H10, SCU494, 12), -+ ASPEED_PULL_DOWN_PINCONF(H11, SCU494, 13), -+ ASPEED_PULL_DOWN_PINCONF(J9, SCU494, 14), -+ ASPEED_PULL_DOWN_PINCONF(J10, SCU494, 15), -+ ASPEED_PULL_DOWN_PINCONF(E9, SCU494, 16), -+ ASPEED_PULL_DOWN_PINCONF(F9, SCU494, 17), -+ ASPEED_PULL_DOWN_PINCONF(F8, SCU494, 18), -+ ASPEED_PULL_DOWN_PINCONF(M13, SCU494, 19), -+ ASPEED_PULL_DOWN_PINCONF(F7, SCU494, 20), -+ ASPEED_PULL_DOWN_PINCONF(D8, SCU494, 21), -+ ASPEED_PULL_DOWN_PINCONF(E8, SCU494, 22), -+ ASPEED_PULL_DOWN_PINCONF(L12, SCU494, 23), -+ ASPEED_PULL_DOWN_PINCONF(F12, SCU494, 24), -+ ASPEED_PULL_DOWN_PINCONF(E12, SCU494, 25), -+ ASPEED_PULL_DOWN_PINCONF(J12, SCU494, 26), -+ ASPEED_PULL_DOWN_PINCONF(G7, SCU494, 27), -+ ASPEED_PULL_DOWN_PINCONF(G8, SCU494, 28), -+ ASPEED_PULL_DOWN_PINCONF(G9, SCU494, 29), -+ ASPEED_PULL_DOWN_PINCONF(G10, SCU494, 30), -+ ASPEED_PULL_DOWN_PINCONF(K12, SCU494, 31), -+ ASPEED_PULL_DOWN_PINCONF(W17, SCU498, 0), -+ ASPEED_PULL_DOWN_PINCONF(V18, SCU498, 1), -+ ASPEED_PULL_DOWN_PINCONF(W18, SCU498, 2), -+ ASPEED_PULL_DOWN_PINCONF(Y17, SCU498, 3), -+ ASPEED_PULL_DOWN_PINCONF(AA18, SCU498, 4), -+ ASPEED_PULL_DOWN_PINCONF(AA13, SCU498, 5), -+ ASPEED_PULL_DOWN_PINCONF(Y18, SCU498, 6), -+ ASPEED_PULL_DOWN_PINCONF(AA12, SCU498, 7), -+ ASPEED_PULL_DOWN_PINCONF(W20, SCU498, 8), -+ ASPEED_PULL_DOWN_PINCONF(V20, SCU498, 9), -+ ASPEED_PULL_DOWN_PINCONF(Y11, SCU498, 10), -+ ASPEED_PULL_DOWN_PINCONF(V14, SCU498, 11), -+ ASPEED_PULL_DOWN_PINCONF(V19, SCU498, 12), -+ ASPEED_PULL_DOWN_PINCONF(W14, SCU498, 13), -+ ASPEED_PULL_DOWN_PINCONF(Y20, SCU498, 14), -+ ASPEED_PULL_DOWN_PINCONF(AB19, SCU498, 15), -+ ASPEED_PULL_DOWN_PINCONF(U21, SCU498, 16), -+ ASPEED_PULL_DOWN_PINCONF(T24, SCU498, 17), -+ ASPEED_PULL_DOWN_PINCONF(V24, SCU498, 18), -+ ASPEED_PULL_DOWN_PINCONF(V22, SCU498, 19), -+ ASPEED_PULL_DOWN_PINCONF(T23, SCU498, 20), -+ ASPEED_PULL_DOWN_PINCONF(AC25, SCU498, 21), -+ ASPEED_PULL_DOWN_PINCONF(AB25, SCU498, 22), -+ ASPEED_PULL_DOWN_PINCONF(AC24, SCU498, 23), -+}; -+ -+static const struct aspeed_pin_config_map aspeed_g7_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 struct aspeed_pinctrl_data aspeed_g7_pinctrl_data = { -+ .pins = aspeed_g7_soc1_pins, -+ .npins = ARRAY_SIZE(aspeed_g7_soc1_pins), -+ .pinmux = { -+ .groups = aspeed_g7_soc1_pingroups, -+ .ngroups = ARRAY_SIZE(aspeed_g7_soc1_pingroups), -+ .functions = aspeed_g7_soc1_funcs, -+ .nfunctions = ARRAY_SIZE(aspeed_g7_soc1_funcs), -+ .configs_g7 = pin_cfg, -+ .nconfigs_g7 = ARRAY_SIZE(pin_cfg), -+ }, -+ .configs = aspeed_g7_configs, -+ .nconfigs = ARRAY_SIZE(aspeed_g7_configs), -+ .confmaps = aspeed_g7_pin_config_map, -+ .nconfmaps = ARRAY_SIZE(aspeed_g7_pin_config_map), -+}; -+ -+static int aspeed_g7_soc1_pinctrl_probe(struct platform_device *pdev) -+{ -+ return aspeed_pinctrl_probe(pdev, &aspeed_g7_soc1_pinctrl_desc, -+ &aspeed_g7_pinctrl_data); -+} -+ -+static const struct of_device_id aspeed_g7_soc1_pinctrl_match[] = { -+ { .compatible = "aspeed,ast2700-soc1-pinctrl" }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, aspeed_g7_soc1_pinctrl_match); -+ -+static struct platform_driver aspeed_g7_soc1_pinctrl_driver = { -+ .probe = aspeed_g7_soc1_pinctrl_probe, -+ .driver = { -+ .name = "aspeed-g7-soc1-pinctrl", -+ .of_match_table = aspeed_g7_soc1_pinctrl_match, -+ .suppress_bind_attrs = true, -+ }, -+}; -+ -+static int __init aspeed_g7_soc1_pinctrl_register(void) -+{ -+ return platform_driver_register(&aspeed_g7_soc1_pinctrl_driver); -+} -+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 2026-04-08 18:03:48.323705083 +0000 -@@ -285,6 +285,32 @@ - return 0; - } - -+int aspeed_g7_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function, -+ unsigned int group) -+{ -+ int i, j; -+ int pin; -+ const struct aspeed_g7_funcfg *funcfg; -+ struct aspeed_pinctrl_data *pinctrl = pinctrl_dev_get_drvdata(pctldev); -+ const struct aspeed_pin_group *pingroup = -+ &pinctrl->pinmux.groups[group]; -+ const struct aspeed_g7_pincfg *pin_cfg = pinctrl->pinmux.configs_g7; -+ -+ for (i = 0; i < pingroup->npins; i++) { -+ pin = pingroup->pins[i]; -+ funcfg = pin_cfg[pin].funcfg; -+ -+ for (j = 0; j < pin_cfg[pin].nfuncfg; j++) { -+ if (strcmp(funcfg[j].name, pingroup->name) == 0) { -+ regmap_update_bits(pinctrl->scu, funcfg[j].reg, -+ funcfg[j].mask, -+ funcfg[j].val); -+ } -+ } -+ } -+ return 0; -+} -+ - static bool aspeed_expr_is_gpio(const struct aspeed_sig_expr *expr) - { - /* -@@ -440,6 +466,27 @@ - return 0; - } - -+int aspeed_g7_gpio_request_enable(struct pinctrl_dev *pctldev, -+ struct pinctrl_gpio_range *range, -+ unsigned int offset) -+{ -+ int i; -+ struct aspeed_pinctrl_data *pinctrl = pinctrl_dev_get_drvdata(pctldev); -+ const struct aspeed_g7_pincfg *pin_cfg = pinctrl->pinmux.configs_g7; -+ const struct aspeed_g7_funcfg *funcfg = pin_cfg[offset].funcfg; -+ -+ for (i = 0; i < pin_cfg[offset].nfuncfg; i++) { -+ if (!strncmp(funcfg[i].name, "GPI", 3)) { -+ regmap_update_bits(pinctrl->scu, funcfg[i].reg, -+ funcfg[i].mask, funcfg[i].val); -+ break; -+ } -+ regmap_update_bits(pinctrl->scu, funcfg[i].reg, funcfg[i].mask, -+ 0); -+ } -+ return 0; -+} -+ - int aspeed_pinctrl_probe(struct platform_device *pdev, - 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 2026-04-08 18:03:48.323705083 +0000 -@@ -70,15 +70,15 @@ - struct regmap *scu; - - const struct pinctrl_pin_desc *pins; -- const unsigned int npins; -+ unsigned int npins; - - const struct aspeed_pin_config *configs; -- const unsigned int nconfigs; -+ unsigned int nconfigs; - - struct aspeed_pinmux_data pinmux; - - const struct aspeed_pin_config_map *confmaps; -- const unsigned int nconfmaps; -+ unsigned int nconfmaps; - }; - - /* Aspeed pinctrl helpers */ -@@ -101,6 +101,11 @@ - int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev, - struct pinctrl_gpio_range *range, - unsigned int offset); -+int aspeed_g7_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function, -+ unsigned int group); -+int aspeed_g7_gpio_request_enable(struct pinctrl_dev *pctldev, -+ struct pinctrl_gpio_range *range, -+ unsigned int offset); - int aspeed_pinctrl_probe(struct platform_device *pdev, - 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 2026-04-08 18:03:48.323705083 +0000 -@@ -792,6 +792,33 @@ - const struct aspeed_sig_expr *expr, bool enabled); - }; - -+struct aspeed_g7_funcfg { -+ char *name; -+ u32 reg; -+ u32 mask; -+ int val; -+}; -+ -+struct aspeed_g7_pincfg { -+ struct aspeed_g7_funcfg *funcfg; -+ unsigned int nfuncfg; -+}; -+ -+#define PIN_CFG(cfg_name, cfg_reg, cfg_mask, cfg_val) \ -+ { \ -+ .name = #cfg_name, .reg = cfg_reg, .mask = cfg_mask, \ -+ .val = cfg_val \ -+ } -+#define FUNCFG_SYM(pin) funcfg_ ## pin -+#define FUNCFG_PTR(pin) (&FUNCFG_SYM(pin)) -+ -+#define FUNCFG_DESCL(pin, ...) \ -+ static const struct aspeed_g7_funcfg FUNCFG_SYM(pin)[] = { __VA_ARGS__ } -+ -+#define PINCFG_PIN(pin) \ -+ [pin] = { .funcfg = (struct aspeed_g7_funcfg *)FUNCFG_PTR(pin), \ -+ .nfuncfg = ARRAY_SIZE(FUNCFG_SYM(pin)) } -+ - struct aspeed_pinmux_data { - struct device *dev; - struct regmap *maps[ASPEED_NR_PINMUX_IPS]; -@@ -799,10 +826,14 @@ - const struct aspeed_pinmux_ops *ops; - - const struct aspeed_pin_group *groups; -- const unsigned int ngroups; -+ unsigned int ngroups; - - const struct aspeed_pin_function *functions; -- const unsigned int nfunctions; -+ unsigned int nfunctions; -+ -+ const struct aspeed_g7_pincfg *configs_g7; -+ unsigned int nconfigs_g7; -+ - }; - - 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 2026-04-08 18:03:49.301687214 +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-04-08 18:03:23.253162611 +0000 -+++ b/drivers/reset/Kconfig 2026-04-08 18:03:35.468939804 +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-04-08 18:03:23.253162611 +0000 -+++ b/drivers/reset/Makefile 2026-04-08 18:03:40.401849820 +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 2026-04-08 18:03:48.301705484 +0000 -@@ -0,0 +1,310 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2024 ASPEED Technology Inc. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define SCU0_RESET_CTRL1 0x200 -+#define SCU0_RESET_CTRL2 0x220 -+#define SCU1_RESET_CTRL1 0x200 -+#define SCU1_RESET_CTRL2 0x220 -+#define SCU1_PCIE3_CTRL 0x908 -+ -+struct aspeed_reset; -+ -+struct ast2700_reset_signal { -+ bool dedicated_clr; /* dedicated reset clr offset */ -+ u32 offset, bit; -+}; -+ -+struct aspeed_reset_info { -+ unsigned int nr_resets; -+ const struct ast2700_reset_signal *signal; -+}; -+ -+struct aspeed_reset { -+ struct reset_controller_dev rcdev; -+ struct aspeed_reset_info *info; -+ spinlock_t lock; /* Protect read-modify-write cycle */ -+ void __iomem *base; -+}; -+ -+static const struct ast2700_reset_signal ast2700_reset0_signals[] = { -+ [SCU0_RESET_SDRAM] = { true, SCU0_RESET_CTRL1, BIT(0) }, -+ [SCU0_RESET_DDRPHY] = { true, SCU0_RESET_CTRL1, BIT(1) }, -+ [SCU0_RESET_RSA] = { true, SCU0_RESET_CTRL1, BIT(2) }, -+ [SCU0_RESET_SHA3] = { true, SCU0_RESET_CTRL1, BIT(3) }, -+ [SCU0_RESET_HACE] = { true, SCU0_RESET_CTRL1, BIT(4) }, -+ [SCU0_RESET_SOC] = { true, SCU0_RESET_CTRL1, BIT(5) }, -+ [SCU0_RESET_VIDEO] = { true, SCU0_RESET_CTRL1, BIT(6) }, -+ [SCU0_RESET_2D] = { true, SCU0_RESET_CTRL1, BIT(7) }, -+ [SCU0_RESET_PCIS] = { true, SCU0_RESET_CTRL1, BIT(8) }, -+ [SCU0_RESET_RVAS0] = { true, SCU0_RESET_CTRL1, BIT(9) }, -+ [SCU0_RESET_RVAS1] = { true, SCU0_RESET_CTRL1, BIT(10) }, -+ [SCU0_RESET_SM3] = { true, SCU0_RESET_CTRL1, BIT(11) }, -+ [SCU0_RESET_SM4] = { true, SCU0_RESET_CTRL1, BIT(12) }, -+ [SCU0_RESET_CRT0] = { true, SCU0_RESET_CTRL1, BIT(13) }, -+ [SCU0_RESET_ECC] = { true, SCU0_RESET_CTRL1, BIT(14) }, -+ [SCU0_RESET_DP_PCI] = { true, SCU0_RESET_CTRL1, BIT(15) }, -+ [SCU0_RESET_UFS] = { true, SCU0_RESET_CTRL1, BIT(16) }, -+ [SCU0_RESET_EMMC] = { true, SCU0_RESET_CTRL1, BIT(17) }, -+ [SCU0_RESET_PCIE1RST] = { true, SCU0_RESET_CTRL1, BIT(18) }, -+ [SCU0_RESET_PCIE1RSTOE] = { true, SCU0_RESET_CTRL1, BIT(19) }, -+ [SCU0_RESET_PCIE0RST] = { true, SCU0_RESET_CTRL1, BIT(20) }, -+ [SCU0_RESET_PCIE0RSTOE] = { true, SCU0_RESET_CTRL1, BIT(21) }, -+ [SCU0_RESET_JTAG] = { true, SCU0_RESET_CTRL1, BIT(22) }, -+ [SCU0_RESET_MCTP0] = { true, SCU0_RESET_CTRL1, BIT(23) }, -+ [SCU0_RESET_MCTP1] = { true, SCU0_RESET_CTRL1, BIT(24) }, -+ [SCU0_RESET_XDMA0] = { true, SCU0_RESET_CTRL1, BIT(25) }, -+ [SCU0_RESET_XDMA1] = { true, SCU0_RESET_CTRL1, BIT(26) }, -+ [SCU0_RESET_H2X1] = { true, SCU0_RESET_CTRL1, BIT(27) }, -+ [SCU0_RESET_DP] = { true, SCU0_RESET_CTRL1, BIT(28) }, -+ [SCU0_RESET_DP_MCU] = { true, SCU0_RESET_CTRL1, BIT(29) }, -+ [SCU0_RESET_SSP] = { true, SCU0_RESET_CTRL1, BIT(30) }, -+ [SCU0_RESET_H2X0] = { true, SCU0_RESET_CTRL1, BIT(31) }, -+ [SCU0_RESET_PORTA_VHUB] = { true, SCU0_RESET_CTRL2, BIT(0) }, -+ [SCU0_RESET_PORTA_PHY3] = { true, SCU0_RESET_CTRL2, BIT(1) }, -+ [SCU0_RESET_PORTA_XHCI] = { true, SCU0_RESET_CTRL2, BIT(2) }, -+ [SCU0_RESET_PORTB_VHUB] = { true, SCU0_RESET_CTRL2, BIT(3) }, -+ [SCU0_RESET_PORTB_PHY3] = { true, SCU0_RESET_CTRL2, BIT(4) }, -+ [SCU0_RESET_PORTB_XHCI] = { true, SCU0_RESET_CTRL2, BIT(5) }, -+ [SCU0_RESET_PORTA_VHUB_EHCI] = { true, SCU0_RESET_CTRL2, BIT(6) }, -+ [SCU0_RESET_PORTB_VHUB_EHCI] = { true, SCU0_RESET_CTRL2, BIT(7) }, -+ [SCU0_RESET_UHCI] = { true, SCU0_RESET_CTRL2, BIT(8) }, -+ [SCU0_RESET_TSP] = { true, SCU0_RESET_CTRL2, BIT(9) }, -+ [SCU0_RESET_E2M0] = { true, SCU0_RESET_CTRL2, BIT(10) }, -+ [SCU0_RESET_E2M1] = { true, SCU0_RESET_CTRL2, BIT(11) }, -+ [SCU0_RESET_VLINK] = { true, SCU0_RESET_CTRL2, BIT(12) }, -+}; -+ -+static const struct ast2700_reset_signal ast2700_reset1_signals[] = { -+ [SCU1_RESET_LPC0] = { true, SCU1_RESET_CTRL1, BIT(0) }, -+ [SCU1_RESET_LPC1] = { true, SCU1_RESET_CTRL1, BIT(1) }, -+ [SCU1_RESET_MII] = { true, SCU1_RESET_CTRL1, BIT(2) }, -+ [SCU1_RESET_PECI] = { true, SCU1_RESET_CTRL1, BIT(3) }, -+ [SCU1_RESET_PWM] = { true, SCU1_RESET_CTRL1, BIT(4) }, -+ [SCU1_RESET_MAC0] = { true, SCU1_RESET_CTRL1, BIT(5) }, -+ [SCU1_RESET_MAC1] = { true, SCU1_RESET_CTRL1, BIT(6) }, -+ [SCU1_RESET_MAC2] = { true, SCU1_RESET_CTRL1, BIT(7) }, -+ [SCU1_RESET_ADC] = { true, SCU1_RESET_CTRL1, BIT(8) }, -+ [SCU1_RESET_SD] = { true, SCU1_RESET_CTRL1, BIT(9) }, -+ [SCU1_RESET_ESPI0] = { true, SCU1_RESET_CTRL1, BIT(10) }, -+ [SCU1_RESET_ESPI1] = { true, SCU1_RESET_CTRL1, BIT(11) }, -+ [SCU1_RESET_JTAG1] = { true, SCU1_RESET_CTRL1, BIT(12) }, -+ [SCU1_RESET_SPI0] = { true, SCU1_RESET_CTRL1, BIT(13) }, -+ [SCU1_RESET_SPI1] = { true, SCU1_RESET_CTRL1, BIT(14) }, -+ [SCU1_RESET_SPI2] = { true, SCU1_RESET_CTRL1, BIT(15) }, -+ [SCU1_RESET_I3C0] = { true, SCU1_RESET_CTRL1, BIT(16) }, -+ [SCU1_RESET_I3C1] = { true, SCU1_RESET_CTRL1, BIT(17) }, -+ [SCU1_RESET_I3C2] = { true, SCU1_RESET_CTRL1, BIT(18) }, -+ [SCU1_RESET_I3C3] = { true, SCU1_RESET_CTRL1, BIT(19) }, -+ [SCU1_RESET_I3C4] = { true, SCU1_RESET_CTRL1, BIT(20) }, -+ [SCU1_RESET_I3C5] = { true, SCU1_RESET_CTRL1, BIT(21) }, -+ [SCU1_RESET_I3C6] = { true, SCU1_RESET_CTRL1, BIT(22) }, -+ [SCU1_RESET_I3C7] = { true, SCU1_RESET_CTRL1, BIT(23) }, -+ [SCU1_RESET_I3C8] = { true, SCU1_RESET_CTRL1, BIT(24) }, -+ [SCU1_RESET_I3C9] = { true, SCU1_RESET_CTRL1, BIT(25) }, -+ [SCU1_RESET_I3C10] = { true, SCU1_RESET_CTRL1, BIT(26) }, -+ [SCU1_RESET_I3C11] = { true, SCU1_RESET_CTRL1, BIT(27) }, -+ [SCU1_RESET_I3C12] = { true, SCU1_RESET_CTRL1, BIT(28) }, -+ [SCU1_RESET_I3C13] = { true, SCU1_RESET_CTRL1, BIT(29) }, -+ [SCU1_RESET_I3C14] = { true, SCU1_RESET_CTRL1, BIT(30) }, -+ [SCU1_RESET_I3C15] = { true, SCU1_RESET_CTRL1, BIT(31) }, -+ [SCU1_RESET_MCU0] = { true, SCU1_RESET_CTRL2, BIT(0) }, -+ [SCU1_RESET_MCU1] = { true, SCU1_RESET_CTRL2, BIT(1) }, -+ [SCU1_RESET_H2A_SPI1] = { true, SCU1_RESET_CTRL2, BIT(2) }, -+ [SCU1_RESET_H2A_SPI2] = { true, SCU1_RESET_CTRL2, BIT(3) }, -+ [SCU1_RESET_UART0] = { true, SCU1_RESET_CTRL2, BIT(4) }, -+ [SCU1_RESET_UART1] = { true, SCU1_RESET_CTRL2, BIT(5) }, -+ [SCU1_RESET_UART2] = { true, SCU1_RESET_CTRL2, BIT(6) }, -+ [SCU1_RESET_UART3] = { true, SCU1_RESET_CTRL2, BIT(7) }, -+ [SCU1_RESET_I2C_FILTER] = { true, SCU1_RESET_CTRL2, BIT(8) }, -+ [SCU1_RESET_CALIPTRA] = { true, SCU1_RESET_CTRL2, BIT(9) }, -+ [SCU1_RESET_XDMA] = { true, SCU1_RESET_CTRL2, BIT(10) }, -+ [SCU1_RESET_FSI] = { true, SCU1_RESET_CTRL2, BIT(12) }, -+ [SCU1_RESET_CAN] = { true, SCU1_RESET_CTRL2, BIT(13) }, -+ [SCU1_RESET_MCTP] = { true, SCU1_RESET_CTRL2, BIT(14) }, -+ [SCU1_RESET_I2C] = { true, SCU1_RESET_CTRL2, BIT(15) }, -+ [SCU1_RESET_UART6] = { true, SCU1_RESET_CTRL2, BIT(16) }, -+ [SCU1_RESET_UART7] = { true, SCU1_RESET_CTRL2, BIT(17) }, -+ [SCU1_RESET_UART8] = { true, SCU1_RESET_CTRL2, BIT(18) }, -+ [SCU1_RESET_UART9] = { true, SCU1_RESET_CTRL2, BIT(19) }, -+ [SCU1_RESET_LTPI0] = { true, SCU1_RESET_CTRL2, BIT(20) }, -+ [SCU1_RESET_VGAL] = { true, SCU1_RESET_CTRL2, BIT(21) }, -+ [SCU1_RESET_LTPI1] = { true, SCU1_RESET_CTRL2, BIT(22) }, -+ [SCU1_RESET_ACE] = { true, SCU1_RESET_CTRL2, BIT(23) }, -+ [SCU1_RESET_E2M] = { true, SCU1_RESET_CTRL2, BIT(24) }, -+ [SCU1_RESET_UHCI] = { true, SCU1_RESET_CTRL2, BIT(25) }, -+ [SCU1_RESET_PORTC_USB2UART] = { true, SCU1_RESET_CTRL2, BIT(26) }, -+ [SCU1_RESET_PORTC_VHUB_EHCI] = { true, SCU1_RESET_CTRL2, BIT(27) }, -+ [SCU1_RESET_PORTD_USB2UART] = { true, SCU1_RESET_CTRL2, BIT(28) }, -+ [SCU1_RESET_PORTD_VHUB_EHCI] = { true, SCU1_RESET_CTRL2, BIT(29) }, -+ [SCU1_RESET_H2X] = { true, SCU1_RESET_CTRL2, BIT(30) }, -+ [SCU1_RESET_I3CDMA] = { true, SCU1_RESET_CTRL2, BIT(31) }, -+ [SCU1_RESET_PCIE2RST] = { false, SCU1_PCIE3_CTRL, BIT(0) }, -+}; -+ -+static inline struct aspeed_reset *to_aspeed_reset(struct reset_controller_dev *rcdev) -+{ -+ return container_of(rcdev, struct aspeed_reset, rcdev); -+} -+ -+static int aspeed_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) -+{ -+ struct aspeed_reset *rc = to_aspeed_reset(rcdev); -+ void __iomem *reg_offset = rc->base + rc->info->signal[id].offset; -+ -+ if (rc->info->signal[id].dedicated_clr) { -+ writel(rc->info->signal[id].bit, reg_offset); -+ } else { -+ guard(spinlock_irqsave)(&rc->lock); -+ writel(readl(reg_offset) & ~rc->info->signal[id].bit, reg_offset); -+ } -+ -+ return 0; -+} -+ -+static int aspeed_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) -+{ -+ struct aspeed_reset *rc = to_aspeed_reset(rcdev); -+ void __iomem *reg_offset = rc->base + rc->info->signal[id].offset; -+ -+ if (rc->info->signal[id].dedicated_clr) { -+ writel(rc->info->signal[id].bit, reg_offset + 0x04); -+ } else { -+ guard(spinlock_irqsave)(&rc->lock); -+ writel(readl(reg_offset) | rc->info->signal[id].bit, reg_offset); -+ } -+ -+ return 0; -+} -+ -+static int aspeed_reset_status(struct reset_controller_dev *rcdev, unsigned long id) -+{ -+ struct aspeed_reset *rc = to_aspeed_reset(rcdev); -+ void __iomem *reg_offset = rc->base + rc->info->signal[id].offset; -+ -+ return (readl(reg_offset) & rc->info->signal[id].bit) ? 1 : 0; -+} -+ -+static const struct reset_control_ops aspeed_reset_ops = { -+ .assert = aspeed_reset_assert, -+ .deassert = aspeed_reset_deassert, -+ .status = aspeed_reset_status, -+}; -+ -+static int aspeed_reset_probe(struct auxiliary_device *adev, -+ const struct auxiliary_device_id *id) -+{ -+ struct aspeed_reset *reset; -+ struct device *dev = &adev->dev; -+ -+ reset = devm_kzalloc(dev, sizeof(*reset), GFP_KERNEL); -+ if (!reset) -+ return -ENOMEM; -+ -+ spin_lock_init(&reset->lock); -+ -+ reset->info = (struct aspeed_reset_info *)id->driver_data; -+ reset->rcdev.owner = THIS_MODULE; -+ reset->rcdev.nr_resets = reset->info->nr_resets; -+ reset->rcdev.ops = &aspeed_reset_ops; -+ reset->rcdev.of_node = dev->parent->of_node; -+ reset->rcdev.dev = dev; -+ reset->rcdev.of_reset_n_cells = 1; -+ reset->base = (void __iomem *)adev->dev.platform_data; -+ -+ dev_set_drvdata(dev, reset); -+ -+ return devm_reset_controller_register(dev, &reset->rcdev); -+} -+ -+static void aspeed_reset_unregister_adev(void *_adev) -+{ -+ struct auxiliary_device *adev = _adev; -+ -+ auxiliary_device_delete(adev); -+ auxiliary_device_uninit(adev); -+} -+ -+static void aspeed_reset_adev_release(struct device *dev) -+{ -+ struct auxiliary_device *adev = to_auxiliary_dev(dev); -+ -+ kfree(adev); -+} -+ -+int aspeed_reset_controller_register(struct device *clk_dev, void __iomem *base, -+ const char *adev_name) -+{ -+ struct auxiliary_device *adev; -+ int ret; -+ -+ adev = kzalloc(sizeof(*adev), GFP_KERNEL); -+ if (!adev) -+ return -ENOMEM; -+ -+ adev->name = adev_name; -+ adev->dev.parent = clk_dev; -+ adev->dev.release = aspeed_reset_adev_release; -+ adev->id = 666u; -+ -+ ret = auxiliary_device_init(adev); -+ if (ret) { -+ kfree(adev); -+ return ret; -+ } -+ -+ ret = auxiliary_device_add(adev); -+ if (ret) { -+ auxiliary_device_uninit(adev); -+ return ret; -+ } -+ -+ adev->dev.platform_data = (__force void *)base; -+ -+ return devm_add_action_or_reset(clk_dev, aspeed_reset_unregister_adev, adev); -+} -+EXPORT_SYMBOL_GPL(aspeed_reset_controller_register); -+ -+static const struct aspeed_reset_info ast2700_reset0_info = { -+ .nr_resets = ARRAY_SIZE(ast2700_reset0_signals), -+ .signal = ast2700_reset0_signals, -+}; -+ -+static const struct aspeed_reset_info ast2700_reset1_info = { -+ .nr_resets = ARRAY_SIZE(ast2700_reset1_signals), -+ .signal = ast2700_reset1_signals, -+}; -+ -+static const struct auxiliary_device_id aspeed_reset_ids[] = { -+ { .name = "reset_aspeed.reset0", .driver_data = (kernel_ulong_t)&ast2700_reset0_info }, -+ { .name = "reset_aspeed.reset1", .driver_data = (kernel_ulong_t)&ast2700_reset1_info }, -+ { } -+}; -+MODULE_DEVICE_TABLE(auxiliary, aspeed_reset_ids); -+ -+static struct auxiliary_driver aspeed_reset_driver = { -+ .probe = aspeed_reset_probe, -+ .id_table = aspeed_reset_ids, -+}; -+ -+static int __init rest_aspeed_init(void) -+{ -+ return auxiliary_driver_register(&aspeed_reset_driver); -+} -+subsys_initcall(rest_aspeed_init); -+ -+MODULE_AUTHOR("Ryan Chen "); -+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 2026-04-08 18:03:48.273705996 +0000 -@@ -10,14 +10,64 @@ - struct aspeed_rtc { - struct rtc_device *rtc_dev; - void __iomem *base; -+ spinlock_t irq_lock; /* interrupt enable register lock */ -+ struct mutex write_mutex; /* serialize registers write */ - }; - - #define RTC_TIME 0x00 - #define RTC_YEAR 0x04 -+#define RTC_ALARM 0x08 - #define RTC_CTRL 0x10 -+#define RTC_ALARM_STATUS 0x14 + #define C22 44 + SIG_EXPR_LIST_DECL_SESG(C22, SD1DAT2, SD1, SIG_DESC_SET(SCU414, 12)); + SIG_EXPR_LIST_DECL_SEMG(C22, PWM12, PWM12G0, PWM12, SIG_DESC_SET(SCU4B4, 12)); +@@ -414,7 +476,7 @@ + #define E21 48 + SIG_EXPR_LIST_DECL_SESG(E21, TXD6, UART6, SIG_DESC_SET(SCU414, 16)); + SIG_EXPR_LIST_DECL_SESG(E21, SD2CLK, SD2, SIG_DESC_SET(SCU4B4, 16), +- SIG_DESC_SET(SCU450, 1)); ++ SIG_DESC_SET(SCU450, 1)); + SIG_EXPR_LIST_DECL_SEMG(E21, SALT9, SALT9G0, SALT9, SIG_DESC_SET(SCU694, 16)); + PIN_DECL_3(E21, GPIOG0, TXD6, SD2CLK, SALT9); + GROUP_DECL(SALT9G0, E21); +@@ -422,7 +484,7 @@ + #define B22 49 + SIG_EXPR_LIST_DECL_SESG(B22, RXD6, UART6, SIG_DESC_SET(SCU414, 17)); + SIG_EXPR_LIST_DECL_SESG(B22, SD2CMD, SD2, SIG_DESC_SET(SCU4B4, 17), +- SIG_DESC_SET(SCU450, 1)); ++ SIG_DESC_SET(SCU450, 1)); + SIG_EXPR_LIST_DECL_SEMG(B22, SALT10, SALT10G0, SALT10, + SIG_DESC_SET(SCU694, 17)); + PIN_DECL_3(B22, GPIOG1, RXD6, SD2CMD, SALT10); +@@ -433,7 +495,7 @@ + #define C21 50 + SIG_EXPR_LIST_DECL_SESG(C21, TXD7, UART7, SIG_DESC_SET(SCU414, 18)); + SIG_EXPR_LIST_DECL_SESG(C21, SD2DAT0, SD2, SIG_DESC_SET(SCU4B4, 18), +- SIG_DESC_SET(SCU450, 1)); ++ SIG_DESC_SET(SCU450, 1)); + SIG_EXPR_LIST_DECL_SEMG(C21, SALT11, SALT11G0, SALT11, + SIG_DESC_SET(SCU694, 18)); + PIN_DECL_3(C21, GPIOG2, TXD7, SD2DAT0, SALT11); +@@ -442,7 +504,7 @@ + #define A22 51 + SIG_EXPR_LIST_DECL_SESG(A22, RXD7, UART7, SIG_DESC_SET(SCU414, 19)); + SIG_EXPR_LIST_DECL_SESG(A22, SD2DAT1, SD2, SIG_DESC_SET(SCU4B4, 19), +- SIG_DESC_SET(SCU450, 1)); ++ SIG_DESC_SET(SCU450, 1)); + SIG_EXPR_LIST_DECL_SEMG(A22, SALT12, SALT12G0, SALT12, + SIG_DESC_SET(SCU694, 19)); + PIN_DECL_3(A22, GPIOG3, RXD7, SD2DAT1, SALT12); +@@ -453,7 +515,7 @@ + #define A21 52 + SIG_EXPR_LIST_DECL_SESG(A21, TXD8, UART8, SIG_DESC_SET(SCU414, 20)); + SIG_EXPR_LIST_DECL_SESG(A21, SD2DAT2, SD2, SIG_DESC_SET(SCU4B4, 20), +- SIG_DESC_SET(SCU450, 1)); ++ SIG_DESC_SET(SCU450, 1)); + SIG_EXPR_LIST_DECL_SEMG(A21, SALT13, SALT13G0, SALT13, + SIG_DESC_SET(SCU694, 20)); + PIN_DECL_3(A21, GPIOG4, TXD8, SD2DAT2, SALT13); +@@ -462,7 +524,7 @@ + #define E20 53 + SIG_EXPR_LIST_DECL_SESG(E20, RXD8, UART8, SIG_DESC_SET(SCU414, 21)); + SIG_EXPR_LIST_DECL_SESG(E20, SD2DAT3, SD2, SIG_DESC_SET(SCU4B4, 21), +- SIG_DESC_SET(SCU450, 1)); ++ SIG_DESC_SET(SCU450, 1)); + SIG_EXPR_LIST_DECL_SEMG(E20, SALT14, SALT14G0, SALT14, + SIG_DESC_SET(SCU694, 21)); + PIN_DECL_3(E20, GPIOG5, RXD8, SD2DAT3, SALT14); +@@ -473,7 +535,7 @@ + #define D21 54 + SIG_EXPR_LIST_DECL_SESG(D21, TXD9, UART9, SIG_DESC_SET(SCU414, 22)); + SIG_EXPR_LIST_DECL_SESG(D21, SD2CD, SD2, SIG_DESC_SET(SCU4B4, 22), +- SIG_DESC_SET(SCU450, 1)); ++ SIG_DESC_SET(SCU450, 1)); + SIG_EXPR_LIST_DECL_SEMG(D21, SALT15, SALT15G0, SALT15, + SIG_DESC_SET(SCU694, 22)); + PIN_DECL_3(D21, GPIOG6, TXD9, SD2CD, SALT15); +@@ -583,116 +645,150 @@ + FUNC_GROUP_DECL(SIOSCI, A15); --#define RTC_UNLOCK BIT(1) --#define RTC_ENABLE BIT(0) -+#define RTC_ENABLE BIT(0) -+#define RTC_UNLOCK BIT(1) -+#define RTC_ALARM_MODE BIT(2) -+#define RTC_ALARM_SEC_ENABLE BIT(3) -+#define RTC_ALARM_MIN_ENABLE BIT(4) -+#define RTC_ALARM_HOUR_ENABLE BIT(5) -+#define RTC_ALARM_MDAY_ENABLE BIT(6) -+ -+#define RTC_ALARM_SEC_CB_STATUS BIT(0) -+#define RTC_ALARM_MIN_STATUS BIT(1) -+#define RTC_ALARM_HOUR_STATUS BIT(2) -+#define RTC_ALARM_MDAY_STATUS BIT(3) -+ -+/* -+ * enable a rtc interrupt -+ */ -+static void aspeed_rtc_int_enable(struct aspeed_rtc *rtc, u32 intr) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&rtc->irq_lock, flags); -+ writel(readl(rtc->base + RTC_CTRL) | intr, rtc->base + RTC_CTRL); -+ spin_unlock_irqrestore(&rtc->irq_lock, flags); -+} -+ -+/* -+ * disable a rtc interrupt -+ */ -+static void aspeed_rtc_int_disable(struct aspeed_rtc *rtc, u32 intr) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&rtc->irq_lock, flags); -+ writel(readl(rtc->base + RTC_CTRL) & ~intr, rtc->base + RTC_CTRL); -+ spin_unlock_irqrestore(&rtc->irq_lock, flags); -+} -+ -+/* -+ * clean a rtc interrupt status -+ */ -+static void aspeed_rtc_clean_alarm(struct aspeed_rtc *rtc) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&rtc->irq_lock, flags); -+ writel(readl(rtc->base + RTC_ALARM_STATUS), rtc->base + RTC_ALARM_STATUS); -+ spin_unlock_irqrestore(&rtc->irq_lock, flags); -+} + #define B20 72 +-SIG_EXPR_LIST_DECL_SEMG(B20, I3C3SCL, HVI3C3, I3C3, SIG_DESC_SET(SCU418, 8)); ++SIG_EXPR_LIST_DECL_SEMG(B20, I3C3SCL, HVI3C3, I3C3, SIG_DESC_SET(SCU418, 8), ++ SIG_DESC_CLEAR(SCU438, 20)); + SIG_EXPR_LIST_DECL_SESG(B20, SCL1, I2C1, SIG_DESC_SET(SCU4B8, 8)); +-PIN_DECL_2(B20, GPIOJ0, I3C3SCL, SCL1); ++SIG_EXPR_LIST_DECL_SESG(B20, SSCL1, SI2C1, SIG_DESC_SET(SCU698, 8)); ++PIN_DECL_3(B20, GPIOJ0, I3C3SCL, SCL1, SSCL1); - static int aspeed_rtc_read_time(struct device *dev, struct rtc_time *tm) - { -@@ -45,7 +95,7 @@ - tm->tm_mon = ((reg2 >> 0) & 0x0f) - 1; - tm->tm_year = year + (cent * 100) - 1900; + #define A20 73 +-SIG_EXPR_LIST_DECL_SEMG(A20, I3C3SDA, HVI3C3, I3C3, SIG_DESC_SET(SCU418, 9)); ++SIG_EXPR_LIST_DECL_SEMG(A20, I3C3SDA, HVI3C3, I3C3, SIG_DESC_SET(SCU418, 9), ++ SIG_DESC_CLEAR(SCU438, 21)); + SIG_EXPR_LIST_DECL_SESG(A20, SDA1, I2C1, SIG_DESC_SET(SCU4B8, 9)); +-PIN_DECL_2(A20, GPIOJ1, I3C3SDA, SDA1); ++SIG_EXPR_LIST_DECL_SESG(A20, SSDA1, SI2C1, SIG_DESC_SET(SCU698, 9)); ++PIN_DECL_3(A20, GPIOJ1, I3C3SDA, SDA1, SSDA1); -- dev_dbg(dev, "%s %ptR", __func__, tm); -+ dev_dbg(dev, "%s %ptR\n", __func__, tm); + GROUP_DECL(HVI3C3, B20, A20); + FUNC_GROUP_DECL(I2C1, B20, A20); ++FUNC_GROUP_DECL(SI2C1, B20, A20); - return 0; - } -@@ -56,6 +106,8 @@ - u32 reg1, reg2, ctrl; - int year, cent; + #define E19 74 +-SIG_EXPR_LIST_DECL_SEMG(E19, I3C4SCL, HVI3C4, I3C4, SIG_DESC_SET(SCU418, 10)); ++SIG_EXPR_LIST_DECL_SEMG(E19, I3C4SCL, HVI3C4, I3C4, SIG_DESC_SET(SCU418, 10), ++ SIG_DESC_CLEAR(SCU438, 22)); + SIG_EXPR_LIST_DECL_SESG(E19, SCL2, I2C2, SIG_DESC_SET(SCU4B8, 10)); +-PIN_DECL_2(E19, GPIOJ2, I3C4SCL, SCL2); ++SIG_EXPR_LIST_DECL_SESG(E19, SSCL2, SI2C2, SIG_DESC_SET(SCU698, 10)); ++PIN_DECL_3(E19, GPIOJ2, I3C4SCL, SCL2, SSCL2); -+ dev_dbg(dev, "%s %ptR\n", __func__, tm); -+ - cent = (tm->tm_year + 1900) / 100; - year = tm->tm_year % 100; + #define D20 75 +-SIG_EXPR_LIST_DECL_SEMG(D20, I3C4SDA, HVI3C4, I3C4, SIG_DESC_SET(SCU418, 11)); ++SIG_EXPR_LIST_DECL_SEMG(D20, I3C4SDA, HVI3C4, I3C4, SIG_DESC_SET(SCU418, 11), ++ SIG_DESC_CLEAR(SCU438, 23)); + SIG_EXPR_LIST_DECL_SESG(D20, SDA2, I2C2, SIG_DESC_SET(SCU4B8, 11)); +-PIN_DECL_2(D20, GPIOJ3, I3C4SDA, SDA2); ++SIG_EXPR_LIST_DECL_SESG(D20, SSDA2, SI2C2, SIG_DESC_SET(SCU698, 11)); ++PIN_DECL_3(D20, GPIOJ3, I3C4SDA, SDA2, SSDA2); -@@ -77,40 +129,215 @@ - return 0; - } + GROUP_DECL(HVI3C4, E19, D20); + FUNC_GROUP_DECL(I2C2, E19, D20); ++FUNC_GROUP_DECL(SI2C2, E19, D20); -+static int aspeed_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) -+{ -+ struct aspeed_rtc *rtc = dev_get_drvdata(dev); -+ unsigned int alarm_enable; -+ -+ dev_dbg(dev, "%s, enabled:%x\n", __func__, enabled); -+ -+ alarm_enable = RTC_ALARM_MODE | RTC_ALARM_SEC_ENABLE | RTC_ALARM_MIN_ENABLE | -+ RTC_ALARM_HOUR_ENABLE | RTC_ALARM_MDAY_ENABLE; -+ if (enabled) -+ aspeed_rtc_int_enable(rtc, alarm_enable); -+ else -+ aspeed_rtc_int_disable(rtc, alarm_enable); -+ -+ return 0; -+} -+ -+static int aspeed_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) -+{ -+ struct aspeed_rtc *rtc = dev_get_drvdata(dev); -+ u32 reg1, reg2; -+ unsigned int alarm_enable; -+ unsigned int alarm_status; -+ -+ if (!(readl(rtc->base + RTC_CTRL) & RTC_ENABLE)) { -+ dev_dbg(dev, "%s failing as rtc disabled\n", __func__); -+ return -EINVAL; -+ } -+ -+ do { -+ reg2 = readl(rtc->base + RTC_YEAR); -+ reg1 = readl(rtc->base + RTC_TIME); -+ } while (reg1 != readl(rtc->base + RTC_TIME)); -+ -+ /* read alarm value */ -+ alarm->time.tm_mday = (reg1 >> 24) & 0x1f; -+ alarm->time.tm_hour = (reg1 >> 16) & 0x1f; -+ alarm->time.tm_min = (reg1 >> 8) & 0x3f; -+ alarm->time.tm_sec = (reg1 >> 0) & 0x3f; -+ -+ dev_dbg(dev, "%s %ptR\n", __func__, &alarm->time); -+ -+ alarm_enable = RTC_ALARM_SEC_ENABLE | RTC_ALARM_MIN_ENABLE | -+ RTC_ALARM_HOUR_ENABLE | RTC_ALARM_MDAY_ENABLE; -+ alarm_status = RTC_ALARM_SEC_CB_STATUS | RTC_ALARM_MIN_STATUS | -+ RTC_ALARM_HOUR_STATUS | RTC_ALARM_MDAY_STATUS; -+ -+ /* don't allow the ALARM read to mess up ALARM_STATUS */ -+ mutex_lock(&rtc->write_mutex); -+ -+ /* alarm is enabled if the interrupt is enabled */ -+ if (readl(rtc->base + RTC_CTRL) & alarm_enable) -+ alarm->enabled = true; -+ else -+ alarm->enabled = false; -+ -+ /* alarm interrupt asserted or not */ -+ if (readl(rtc->base + RTC_ALARM_STATUS) & alarm_status) -+ alarm->pending = true; -+ else -+ alarm->pending = false; -+ -+ mutex_unlock(&rtc->write_mutex); -+ -+ return 0; -+} -+ -+static int aspeed_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) -+{ -+ struct aspeed_rtc *rtc = dev_get_drvdata(dev); -+ unsigned int alarm_enable; -+ u32 reg; -+ -+ if (!(readl(rtc->base + RTC_CTRL) & RTC_ENABLE)) { -+ dev_dbg(dev, "%s failing as rtc disabled\n", __func__); -+ return -EINVAL; -+ } -+ -+ dev_dbg(dev, "%s %ptR\n", __func__, &alarm->time); -+ -+ alarm_enable = RTC_ALARM_MODE | RTC_ALARM_SEC_ENABLE | RTC_ALARM_MIN_ENABLE | -+ RTC_ALARM_HOUR_ENABLE | RTC_ALARM_MDAY_ENABLE; -+ -+ /* don't allow the ALARM read to mess up ALARM_STATUS */ -+ mutex_lock(&rtc->write_mutex); -+ -+ /* write the new alarm time */ -+ reg = (alarm->time.tm_mday << 24) | (alarm->time.tm_hour << 16) | -+ (alarm->time.tm_min << 8) | alarm->time.tm_sec; -+ writel(reg, rtc->base + RTC_ALARM); -+ -+ /* alarm is enabled if the interrupt is enabled */ -+ if (alarm->enabled) -+ aspeed_rtc_int_enable(rtc, alarm_enable); -+ else -+ aspeed_rtc_int_disable(rtc, alarm_enable); -+ -+ mutex_unlock(&rtc->write_mutex); -+ -+ return 0; -+} -+ - static const struct rtc_class_ops aspeed_rtc_ops = { -- .read_time = aspeed_rtc_read_time, -- .set_time = aspeed_rtc_set_time, -+ .read_time = aspeed_rtc_read_time, -+ .set_time = aspeed_rtc_set_time, -+ .alarm_irq_enable = aspeed_rtc_alarm_irq_enable, -+ .read_alarm = aspeed_rtc_read_alarm, -+ .set_alarm = aspeed_rtc_set_alarm, - }; + #define C19 76 + SIG_EXPR_LIST_DECL_SESG(C19, I3C5SCL, I3C5, SIG_DESC_SET(SCU418, 12)); + SIG_EXPR_LIST_DECL_SESG(C19, SCL3, I2C3, SIG_DESC_SET(SCU4B8, 12)); +-PIN_DECL_2(C19, GPIOJ4, I3C5SCL, SCL3); ++SIG_EXPR_LIST_DECL_SESG(C19, SSCL3, SI2C3, SIG_DESC_SET(SCU698, 12)); ++PIN_DECL_3(C19, GPIOJ4, I3C5SCL, SCL3, SSCL3); -+static irqreturn_t aspeed_rtc_irq(int irq, void *dev_id) -+{ -+ struct aspeed_rtc *rtc = dev_id; -+ unsigned int alarm_enable; -+ -+ alarm_enable = RTC_ALARM_MODE | RTC_ALARM_SEC_ENABLE | RTC_ALARM_MIN_ENABLE | -+ RTC_ALARM_HOUR_ENABLE | RTC_ALARM_MDAY_ENABLE; -+ aspeed_rtc_int_disable(rtc, alarm_enable); -+ aspeed_rtc_clean_alarm(rtc); -+ -+ return IRQ_HANDLED; -+} -+ - static int aspeed_rtc_probe(struct platform_device *pdev) - { - struct aspeed_rtc *rtc; -+ unsigned int irq; -+ int rc; -+ u32 ctrl; + #define A19 77 + SIG_EXPR_LIST_DECL_SESG(A19, I3C5SDA, I3C5, SIG_DESC_SET(SCU418, 13)); + SIG_EXPR_LIST_DECL_SESG(A19, SDA3, I2C3, SIG_DESC_SET(SCU4B8, 13)); +-PIN_DECL_2(A19, GPIOJ5, I3C5SDA, SDA3); ++SIG_EXPR_LIST_DECL_SESG(A19, SSDA3, SI2C3, SIG_DESC_SET(SCU698, 13)); ++PIN_DECL_3(A19, GPIOJ5, I3C5SDA, SDA3, SSDA3); - rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); - if (!rtc) - return -ENOMEM; + FUNC_GROUP_DECL(I3C5, C19, A19); + FUNC_GROUP_DECL(I2C3, C19, A19); ++FUNC_GROUP_DECL(SI2C3, C19, A19); - rtc->base = devm_platform_ioremap_resource(pdev, 0); -- if (IS_ERR(rtc->base)) -+ if (IS_ERR(rtc->base)) { -+ dev_err(&pdev->dev, "cannot ioremap resource for rtc\n"); - return PTR_ERR(rtc->base); -+ } + #define C20 78 + SIG_EXPR_LIST_DECL_SESG(C20, I3C6SCL, I3C6, SIG_DESC_SET(SCU418, 14)); + SIG_EXPR_LIST_DECL_SESG(C20, SCL4, I2C4, SIG_DESC_SET(SCU4B8, 14)); +-PIN_DECL_2(C20, GPIOJ6, I3C6SCL, SCL4); ++SIG_EXPR_LIST_DECL_SESG(C20, SSCL4, SI2C4, SIG_DESC_SET(SCU698, 14)); ++PIN_DECL_3(C20, GPIOJ6, I3C6SCL, SCL4, SSCL4); - rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev); - if (IS_ERR(rtc->rtc_dev)) - return PTR_ERR(rtc->rtc_dev); + #define D19 79 + SIG_EXPR_LIST_DECL_SESG(D19, I3C6SDA, I3C6, SIG_DESC_SET(SCU418, 15)); + SIG_EXPR_LIST_DECL_SESG(D19, SDA4, I2C4, SIG_DESC_SET(SCU4B8, 15)); +-PIN_DECL_2(D19, GPIOJ7, I3C6SDA, SDA4); ++SIG_EXPR_LIST_DECL_SESG(D19, SSDA4, SI2C4, SIG_DESC_SET(SCU698, 15)); ++PIN_DECL_3(D19, GPIOJ7, I3C6SDA, SDA4, SSDA4); -+ spin_lock_init(&rtc->irq_lock); -+ mutex_init(&rtc->write_mutex); -+ -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) -+ return irq; -+ -+ rc = devm_request_irq(&pdev->dev, irq, aspeed_rtc_irq, -+ 0, pdev->name, rtc); -+ if (rc) { -+ dev_err(&pdev->dev, "interrupt number %d is not available.\n", irq); -+ goto err; -+ } -+ - platform_set_drvdata(pdev, rtc); + FUNC_GROUP_DECL(I3C6, C20, D19); + FUNC_GROUP_DECL(I2C4, C20, D19); ++FUNC_GROUP_DECL(SI2C4, C20, D19); -+ device_init_wakeup(&pdev->dev, true); -+ - rtc->rtc_dev->ops = &aspeed_rtc_ops; - rtc->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_1900; - rtc->rtc_dev->range_max = 38814989399LL; /* 3199-12-31 23:59:59 */ + #define A11 80 + SIG_EXPR_LIST_DECL_SESG(A11, SCL5, I2C5, SIG_DESC_SET(SCU418, 16)); +-PIN_DECL_1(A11, GPIOK0, SCL5); ++SIG_EXPR_LIST_DECL_SESG(A11, SSCL5, SI2C5, SIG_DESC_SET(SCU4B8, 16)); ++PIN_DECL_2(A11, GPIOK0, SCL5, SSCL5); -- return devm_rtc_register_device(rtc->rtc_dev); -+ /* -+ * In devm_rtc_register_device, -+ * rtc_hctosys read time from RTC to check hardware status. -+ * 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); -+ -+ if (!(ctrl & RTC_ENABLE)) { -+ 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); -+ -+ /* 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) { -+ dev_err(&pdev->dev, "can't register rtc device\n"); -+ goto err; -+ } -+ -+ return 0; -+ -+err: -+ return rc; - } + #define C11 81 + SIG_EXPR_LIST_DECL_SESG(C11, SDA5, I2C5, SIG_DESC_SET(SCU418, 17)); +-PIN_DECL_1(C11, GPIOK1, SDA5); ++SIG_EXPR_LIST_DECL_SESG(C11, SSDA5, SI2C5, SIG_DESC_SET(SCU4B8, 17)); ++PIN_DECL_2(C11, GPIOK1, SDA5, SSDA5); - static const struct of_device_id aspeed_rtc_match[] = { - { .compatible = "aspeed,ast2400-rtc", }, - { .compatible = "aspeed,ast2500-rtc", }, - { .compatible = "aspeed,ast2600-rtc", }, -+ { .compatible = "aspeed,ast2700-rtc", }, - {} - }; - 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 2026-04-08 18:03:48.310705320 +0000 -@@ -4,6 +4,12 @@ + FUNC_GROUP_DECL(I2C5, A11, C11); ++FUNC_GROUP_DECL(SI2C5, A11, C11); - menu "ASPEED SoC drivers" + #define D12 82 + SIG_EXPR_LIST_DECL_SESG(D12, SCL6, I2C6, SIG_DESC_SET(SCU418, 18)); +-PIN_DECL_1(D12, GPIOK2, SCL6); ++SIG_EXPR_LIST_DECL_SESG(D12, SSCL6, SI2C6, SIG_DESC_SET(SCU4B8, 18)); ++PIN_DECL_2(D12, GPIOK2, SCL6, SSCL6); -+config ASPEED_BMC_DEV -+ tristate "ASPEED BMC Device" -+ -+config ASPEED_HOST_BMC_DEV -+ tristate "ASPEED Host BMC Device" -+ - config ASPEED_LPC_CTRL - tristate "ASPEED LPC firmware cycle control" - select REGMAP -@@ -24,6 +30,13 @@ - allows the BMC to listen on and save the data written by - the host to an arbitrary LPC I/O port. + #define E13 83 + SIG_EXPR_LIST_DECL_SESG(E13, SDA6, I2C6, SIG_DESC_SET(SCU418, 19)); +-PIN_DECL_1(E13, GPIOK3, SDA6); ++SIG_EXPR_LIST_DECL_SESG(E13, SSDA6, SI2C6, SIG_DESC_SET(SCU4B8, 19)); ++PIN_DECL_2(E13, GPIOK3, SDA6, SSDA6); -+config ASPEED_SSP -+ tristate "ASPEED SSP loader" -+ default n -+ help -+ Driver for loading secondary-service-processor binary -+ -+ - config ASPEED_UART_ROUTING - tristate "ASPEED uart routing control" - select REGMAP -@@ -34,6 +47,16 @@ - users to perform runtime configuration of the RX muxes among - the UART controllers and I/O pins. + FUNC_GROUP_DECL(I2C6, D12, E13); ++FUNC_GROUP_DECL(SI2C6, D12, E13); -+config ASPEED_LPC_MAILBOX -+ tristate "ASPEED LPC mailbox support" -+ select REGMAP -+ select MFD_SYSCON -+ default ARCH_ASPEED -+ help -+ Provides a driver to control the LPC mailbox which possesses -+ up to 32 data registers for the communication between the Host -+ and the BMC over LPC. -+ - config ASPEED_P2A_CTRL - tristate "ASPEED P2A (VGA MMIO to BMC) bridge control" - select REGMAP -@@ -52,6 +75,100 @@ - help - Say yes to support decoding of ASPEED BMC information. + #define D11 84 + SIG_EXPR_LIST_DECL_SESG(D11, SCL7, I2C7, SIG_DESC_SET(SCU418, 20)); +-PIN_DECL_1(D11, GPIOK4, SCL7); ++SIG_EXPR_LIST_DECL_SESG(D11, SSCL7, SI2C7, SIG_DESC_SET(SCU4B8, 20)); ++PIN_DECL_2(D11, GPIOK4, SCL7, SSCL7); -+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). -+ -+config ASPEED_XDMA -+ tristate "ASPEED XDMA Engine Driver" -+ select REGMAP -+ select MFD_SYSCON -+ depends on HAS_DMA -+ help -+ Enables support for the XDMA Engine found on the ASPEED BMC -+ SoCs. The XDMA engine can perform PCIe DMA operations between the BMC -+ and a host processor. The driver provides ioctl() interface to reset -+ and initialize engine. -+ -+config ASPEED_LPC_PCC -+ tristate "Aspeed Post Code Capture support" -+ depends on ARCH_ASPEED && REGMAP && MFD_SYSCON -+ help -+ Provides a driver to control the LPC PCC interface, -+ allowing the BMC to snoop data bytes written by the -+ the host to an arbitrary LPC I/O port. -+ -+config ASPEED_UDMA -+ tristate "Aspeed UDMA Engine Driver" -+ depends on ARCH_ASPEED && REGMAP && MFD_SYSCON && HAS_DMA -+ help -+ Enable support for the Aspeed UDMA Engine found on the Aspeed AST2XXX -+ SOCs. The UDMA engine can perform UART DMA operations between the memory -+ buffer and the UART/VUART devices. -+ -+config ASPEED_MBOX -+ bool "Enable support for the ASPEED MBOX driver" -+ depends on ARCH_ASPEED -+ help -+ Enable support for the ASPEED MBOX driver. This driver -+ provides a mailbox client to the ASPEED BMC SoC IPC. -+ -+config ASPEED_MCTP -+ tristate "Aspeed MCTP Controller support" -+ depends on REGMAP && MFD_SYSCON -+ help -+ Enable support for Aspeed MCTP Controller. -+ The MCTP controller allows the BMC to communicate with devices on -+ the host PCIe network. -+ -+config ASPEED_DISP_INTF -+ bool "ASPEED Display Interface driver" -+ select REGMAP -+ select MFD_SYSCON -+ default ARCH_ASPEED -+ help -+ Say yes to support control the display interface of ASPEED BMC. -+ -+config ASPEED_UDMA -+ tristate "Aspeed UDMA Engine Driver" -+ depends on ARCH_ASPEED && REGMAP && MFD_SYSCON && HAS_DMA -+ help -+ Enable support for the Aspeed UDMA Engine found on the Aspeed AST2XXX -+ 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_OTP -+ tristate -+ help -+ Enable driver support for Aspeed OTP driver. Each bit in One -+ Time Prgrammable (OTP) memory is capable to be programmed once. -+ The OTP driver performs basic read/program operations of -+ OTP memory. -+ -+config AST2600_OTP -+ tristate "AST2600 OTP Driver" -+ select ASPEED_OTP -+ depends on ARCH_ASPEED -+ help -+ Enable driver support for Aspeed AST2600 OTP driver. -+ -+config AST2700_OTP -+ tristate "AST2700 OTP Driver" -+ select ASPEED_OTP -+ depends on ARCH_ASPEED -+ help -+ Enable driver support for Aspeed AST2700 OTP driver. -+ -+source "drivers/soc/aspeed/espi/Kconfig" -+source "drivers/soc/aspeed/rvas/Kconfig" -+ - endmenu + #define E11 85 + SIG_EXPR_LIST_DECL_SESG(E11, SDA7, I2C7, SIG_DESC_SET(SCU418, 21)); +-PIN_DECL_1(E11, GPIOK5, SDA7); ++SIG_EXPR_LIST_DECL_SESG(E11, SSDA7, SI2C7, SIG_DESC_SET(SCU4B8, 21)); ++PIN_DECL_2(E11, GPIOK5, SDA7, SSDA7); - 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 2026-04-08 18:03:48.360704407 +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 - obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o - obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o -+obj-$(CONFIG_ASPEED_LPC_MAILBOX) += aspeed-lpc-mbox.o -+obj-$(CONFIG_ASPEED_LPC_PCC) += aspeed-lpc-pcc.o -+obj-$(CONFIG_ASPEED_UDMA) += aspeed-udma.o - obj-$(CONFIG_ASPEED_UART_ROUTING) += aspeed-uart-routing.o -+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_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_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 ---- a/drivers/soc/aspeed/aspeed-bmc-dev.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/soc/aspeed/aspeed-bmc-dev.c 2026-04-08 18:03:48.310705320 +0000 -@@ -0,0 +1,703 @@ -+// 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 SCU_TRIGGER_MSI -+ -+/* AST2600 SCU */ -+#define ASPEED_SCU04 0x04 -+#define AST2600A3_SCU04 0x05030303 -+#define ASPEED_SCUC20 0xC20 -+#define ASPEED_SCUC24 0xC24 -+#define MSI_ROUTING_MASK GENMASK(11, 10) -+#define PCIDEV1_INTX_MSI_HOST2BMC_EN BIT(18) -+#define MSI_ROUTING_PCIe2LPC_PCIDEV0 (0x1 << 10) -+#define MSI_ROUTING_PCIe2LPC_PCIDEV1 (0x2 << 10) -+/* AST2700 SCU */ -+#define SCU0_REVISION_ID 0x0 -+#define REVISION_ID GENMASK(23, 16) -+#define SCU0_PCIE_CONF_CTRL 0x970 -+/* Host2BMC */ -+#define ASPEED_BMC_MEM_BAR 0xF10 -+#define PCIE2PCI_MEM_BAR_ENABLE BIT(1) -+#define HOST2BMC_MEM_BAR_ENABLE BIT(0) -+#define ASPEED_BMC_MEM_BAR_REMAP 0xF18 -+ -+#define ASPEED_BMC_SHADOW_CTRL 0xF50 -+#define READ_ONLY_MASK BIT(31) -+#define MASK_BAR1 BIT(2) -+#define MASK_BAR0 BIT(1) -+#define SHADOW_CFG BIT(0) -+ -+#define ASPEED_BMC_HOST2BMC_Q1 0xA000 -+#define ASPEED_BMC_HOST2BMC_Q2 0xA010 -+#define ASPEED_BMC_BMC2HOST_Q1 0xA020 -+#define ASPEED_BMC_BMC2HOST_Q2 0xA030 -+#define ASPEED_BMC_BMC2HOST_STS 0xA040 -+#define BMC2HOST_INT_STS_DOORBELL BIT(31) -+#define BMC2HOST_ENABLE_INTB BIT(30) -+#define BMC2HOST_Q1_FULL BIT(27) -+#define BMC2HOST_Q1_EMPTY BIT(26) -+#define BMC2HOST_Q2_FULL BIT(25) -+#define BMC2HOST_Q2_EMPTY BIT(24) -+#define BMC2HOST_Q1_FULL_UNMASK BIT(23) -+#define BMC2HOST_Q1_EMPTY_UNMASK BIT(22) -+#define BMC2HOST_Q2_FULL_UNMASK BIT(21) -+#define BMC2HOST_Q2_EMPTY_UNMASK BIT(20) -+ -+#define ASPEED_BMC_HOST2BMC_STS 0xA044 -+#define HOST2BMC_INT_STS_DOORBELL BIT(31) -+#define HOST2BMC_ENABLE_INTB BIT(30) -+#define HOST2BMC_Q1_FULL BIT(27) -+#define HOST2BMC_Q1_EMPTY BIT(26) -+#define HOST2BMC_Q2_FULL BIT(25) -+#define HOST2BMC_Q2_EMPTY BIT(24) -+#define HOST2BMC_Q1_FULL_UNMASK BIT(23) -+#define HOST2BMC_Q1_EMPTY_UNMASK BIT(22) -+#define HOST2BMC_Q2_FULL_UNMASK BIT(21) -+#define HOST2BMC_Q2_EMPTY_UNMASK BIT(20) -+ -+#define ASPEED_SCU_PCIE_CONF_CTRL 0xC20 -+#define SCU_PCIE_CONF_BMC_DEV_EN BIT(8) -+#define SCU_PCIE_CONF_BMC_DEV_EN_MMIO BIT(9) -+#define SCU_PCIE_CONF_BMC_DEV_EN_MSI BIT(11) -+#define SCU_PCIE_CONF_BMC_DEV_EN_IRQ BIT(13) -+#define SCU_PCIE_CONF_BMC_DEV_EN_DMA BIT(14) -+#define SCU_PCIE_CONF_BMC_DEV_EN_E2L BIT(15) -+#define SCU_PCIE_CONF_BMC_DEV_EN_LPC_DECODE BIT(21) -+ -+#define ASPEED_SCU_BMC_DEV_CLASS 0xC68 -+ -+#define ASPEED_QUEUE_NUM 2 -+enum queue_index { -+ QUEUE1 = 0, -+ QUEUE2, -+}; -+ -+struct aspeed_platform { -+ int (*init)(struct platform_device *pdev); -+ ssize_t (*queue_rx)(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, -+ char *buf, loff_t off, size_t count); -+ ssize_t (*queue_tx)(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, -+ char *buf, loff_t off, size_t count); -+}; -+ -+struct aspeed_queue_message { -+ /* Queue waiters for idle engine */ -+ wait_queue_head_t tx_wait; -+ wait_queue_head_t rx_wait; -+ struct kernfs_node *kn; -+ struct bin_attribute bin; -+ int index; -+ struct aspeed_bmc_device *bmc_device; -+}; -+ -+struct aspeed_bmc_device { -+ unsigned char *host2bmc_base_virt; -+ struct device *dev; -+ struct miscdevice miscdev; -+ int id; -+ void __iomem *reg_base; -+ dma_addr_t bmc_mem_phy; -+ phys_addr_t bmc_mem_size; -+ void *bmc_mem_cpu; -+ -+ int pcie2lpc; -+ int irq; -+ -+ struct aspeed_queue_message queue[ASPEED_QUEUE_NUM]; -+ -+ const struct aspeed_platform *platform; -+ -+ /* AST2700 */ -+ struct regmap *device; -+ struct regmap *e2m; -+ -+ struct regmap *scu; -+ int pcie_irq; -+}; -+ -+static struct aspeed_bmc_device *file_aspeed_bmc_device(struct file *file) -+{ -+ return container_of(file->private_data, struct aspeed_bmc_device, -+ miscdev); -+} -+ -+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; -+ -+ if (vsize > bmc_device->bmc_mem_size) -+ return -EINVAL; -+ -+ return dma_mmap_coherent(bmc_device->dev, vma, -+ bmc_device->bmc_mem_cpu, -+ bmc_device->bmc_mem_phy, -+ bmc_device->bmc_mem_size); -+ -+} -+ -+static const struct file_operations aspeed_bmc_device_fops = { -+ .owner = THIS_MODULE, -+ .mmap = aspeed_bmc_device_mmap, -+}; -+ -+static ssize_t aspeed_ast2600_queue_rx(struct file *filp, struct kobject *kobj, -+ struct bin_attribute *attr, char *buf, loff_t off, -+ size_t count) -+{ -+ struct aspeed_queue_message *queue = attr->private; -+ struct aspeed_bmc_device *bmc_device = queue->bmc_device; -+ int index = queue->index; -+ u32 *data = (u32 *)buf; -+ u32 scu_id; -+ int ret; -+ -+ ret = wait_event_interruptible(queue->rx_wait, -+ !(readl(bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS) & -+ ((index == QUEUE1) ? HOST2BMC_Q1_EMPTY : HOST2BMC_Q2_EMPTY))); -+ if (ret) -+ return -EINTR; -+ -+ data[0] = readl(bmc_device->reg_base + -+ ((index == QUEUE1) ? ASPEED_BMC_HOST2BMC_Q1 : ASPEED_BMC_HOST2BMC_Q2)); -+ -+ regmap_read(bmc_device->scu, ASPEED_SCU04, &scu_id); -+ if (scu_id == AST2600A3_SCU04) { -+ writel(BMC2HOST_INT_STS_DOORBELL | BMC2HOST_ENABLE_INTB, -+ bmc_device->reg_base + ASPEED_BMC_BMC2HOST_STS); -+ } else { -+ //A0 : BIT(12) A1 : BIT(15) -+ regmap_update_bits(bmc_device->scu, 0x560, BIT(15), BIT(15)); -+ regmap_update_bits(bmc_device->scu, 0x560, BIT(15), 0); -+ } -+ -+ return sizeof(u32); -+} -+ -+static ssize_t aspeed_ast2600_queue_tx(struct file *filp, struct kobject *kobj, -+ struct bin_attribute *attr, char *buf, loff_t off, -+ size_t count) -+{ -+ struct aspeed_queue_message *queue = attr->private; -+ struct aspeed_bmc_device *bmc_device = queue->bmc_device; -+ int index = queue->index; -+ u32 tx_buff; -+ u32 scu_id; -+ int ret; -+ -+ if (count != sizeof(u32)) -+ return -EINVAL; -+ -+ ret = wait_event_interruptible(queue->tx_wait, -+ !(readl(bmc_device->reg_base + ASPEED_BMC_BMC2HOST_STS) & -+ ((index == QUEUE1) ? BMC2HOST_Q1_FULL : BMC2HOST_Q2_FULL))); -+ if (ret) -+ return -EINTR; -+ -+ memcpy(&tx_buff, buf, 4); -+ writel(tx_buff, bmc_device->reg_base + ((index == QUEUE1) ? ASPEED_BMC_BMC2HOST_Q1 : -+ ASPEED_BMC_BMC2HOST_Q2)); -+ -+ /* trigger to host -+ * Only After AST2600A3 support DoorBell MSI -+ */ -+ regmap_read(bmc_device->scu, ASPEED_SCU04, &scu_id); -+ if (scu_id == AST2600A3_SCU04) { -+ writel(BMC2HOST_INT_STS_DOORBELL | BMC2HOST_ENABLE_INTB, -+ bmc_device->reg_base + ASPEED_BMC_BMC2HOST_STS); -+ } else { -+ //A0 : BIT(12) A1 : BIT(15) -+ regmap_update_bits(bmc_device->scu, 0x560, BIT(15), BIT(15)); -+ regmap_update_bits(bmc_device->scu, 0x560, BIT(15), 0); -+ } -+ -+ return sizeof(u32); -+} -+ -+static ssize_t aspeed_ast2700_queue_rx(struct file *filp, struct kobject *kobj, -+ struct bin_attribute *attr, char *buf, loff_t off, -+ size_t count) -+{ -+ struct aspeed_queue_message *queue = attr->private; -+ struct aspeed_bmc_device *bmc_device = queue->bmc_device; -+ int index = queue->index; -+ u32 *data = (u32 *)buf; -+ int ret; -+ -+ ret = wait_event_interruptible(queue->rx_wait, -+ !(readl(bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS) & -+ ((index == QUEUE1) ? HOST2BMC_Q1_EMPTY : HOST2BMC_Q2_EMPTY))); -+ if (ret) -+ return -EINTR; -+ -+ data[0] = readl(bmc_device->reg_base + -+ ((index == QUEUE1) ? ASPEED_BMC_HOST2BMC_Q1 : ASPEED_BMC_HOST2BMC_Q2)); -+ -+ writel(BMC2HOST_INT_STS_DOORBELL | BMC2HOST_ENABLE_INTB, -+ bmc_device->reg_base + ASPEED_BMC_BMC2HOST_STS); -+ -+ return sizeof(u32); -+} -+ -+static ssize_t aspeed_ast2700_queue_tx(struct file *filp, struct kobject *kobj, -+ struct bin_attribute *attr, char *buf, loff_t off, -+ size_t count) -+{ -+ struct aspeed_queue_message *queue = attr->private; -+ struct aspeed_bmc_device *bmc_device = queue->bmc_device; -+ int index = queue->index; -+ u32 tx_buff; -+ int ret; -+ -+ if (count != sizeof(u32)) -+ return -EINVAL; -+ -+ ret = wait_event_interruptible(queue->tx_wait, -+ !(readl(bmc_device->reg_base + ASPEED_BMC_BMC2HOST_STS) & -+ ((index == QUEUE1) ? BMC2HOST_Q1_FULL : BMC2HOST_Q2_FULL))); -+ if (ret) -+ return -EINTR; -+ -+ memcpy(&tx_buff, buf, 4); -+ writel(tx_buff, bmc_device->reg_base + ((index == QUEUE1) ? ASPEED_BMC_BMC2HOST_Q1 : -+ ASPEED_BMC_BMC2HOST_Q2)); -+ -+ writel(BMC2HOST_INT_STS_DOORBELL | BMC2HOST_ENABLE_INTB, -+ bmc_device->reg_base + ASPEED_BMC_BMC2HOST_STS); -+ -+ return sizeof(u32); -+} -+ -+/* AST2600 */ -+static irqreturn_t aspeed_bmc_dev_pcie_isr(int irq, void *dev_id) -+{ -+ struct aspeed_bmc_device *bmc_device = dev_id; -+ -+ while (!(readl(bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS) & HOST2BMC_Q1_EMPTY)) -+ readl(bmc_device->reg_base + ASPEED_BMC_HOST2BMC_Q1); -+ -+ while (!(readl(bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS) & HOST2BMC_Q2_EMPTY)) -+ readl(bmc_device->reg_base + ASPEED_BMC_HOST2BMC_Q2); -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t aspeed_bmc_dev_isr(int irq, void *dev_id) -+{ -+ struct aspeed_bmc_device *bmc_device = dev_id; -+ u32 host2bmc_q_sts = readl(bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS); -+ -+ if (host2bmc_q_sts & HOST2BMC_INT_STS_DOORBELL) -+ writel(HOST2BMC_INT_STS_DOORBELL, bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS); -+ -+ if (host2bmc_q_sts & HOST2BMC_ENABLE_INTB) -+ writel(HOST2BMC_ENABLE_INTB, bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS); -+ -+ if (host2bmc_q_sts & HOST2BMC_Q1_FULL) -+ dev_info(bmc_device->dev, "Q1 Full\n"); -+ -+ if (host2bmc_q_sts & HOST2BMC_Q2_FULL) -+ dev_info(bmc_device->dev, "Q2 Full\n"); -+ -+ if (!(readl(bmc_device->reg_base + ASPEED_BMC_BMC2HOST_STS) & BMC2HOST_Q1_FULL)) -+ wake_up_interruptible(&bmc_device->queue[QUEUE1].tx_wait); -+ -+ if (!(readl(bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS) & HOST2BMC_Q1_EMPTY)) -+ wake_up_interruptible(&bmc_device->queue[QUEUE1].rx_wait); -+ -+ if (!(readl(bmc_device->reg_base + ASPEED_BMC_BMC2HOST_STS) & BMC2HOST_Q2_FULL)) -+ wake_up_interruptible(&bmc_device->queue[QUEUE2].tx_wait); -+ -+ if (!(readl(bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS) & HOST2BMC_Q2_EMPTY)) -+ wake_up_interruptible(&bmc_device->queue[QUEUE2].rx_wait); -+ -+ return IRQ_HANDLED; -+} -+ -+static int aspeed_ast2600_init(struct platform_device *pdev) -+{ -+ struct aspeed_bmc_device *bmc_device = platform_get_drvdata(pdev); -+ struct device *dev = &pdev->dev; -+ u32 pcie_config_ctl = SCU_PCIE_CONF_BMC_DEV_EN_IRQ | -+ SCU_PCIE_CONF_BMC_DEV_EN_MMIO | SCU_PCIE_CONF_BMC_DEV_EN; -+ u32 scu_id; -+ -+ bmc_device->scu = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,scu"); -+ if (IS_ERR(bmc_device->scu)) { -+ dev_err(&pdev->dev, "failed to find SCU regmap\n"); -+ return PTR_ERR(bmc_device->scu); -+ } -+ -+ if (bmc_device->pcie2lpc) -+ pcie_config_ctl |= SCU_PCIE_CONF_BMC_DEV_EN_E2L | -+ SCU_PCIE_CONF_BMC_DEV_EN_LPC_DECODE; -+ -+ regmap_update_bits(bmc_device->scu, ASPEED_SCU_PCIE_CONF_CTRL, -+ pcie_config_ctl, pcie_config_ctl); -+ -+ /* update class code to others as it is a MFD device */ -+ regmap_write(bmc_device->scu, ASPEED_SCU_BMC_DEV_CLASS, 0xff000000); -+ -+#ifdef SCU_TRIGGER_MSI -+ //SCUC24[17]: Enable PCI device 1 INTx/MSI from SCU560[15]. Will be added in next version -+ regmap_update_bits(bmc_device->scu, ASPEED_SCUC20, BIT(11) | BIT(14), BIT(11) | BIT(14)); -+ -+ regmap_read(bmc_device->scu, ASPEED_SCU04, &scu_id); -+ if (scu_id == AST2600A3_SCU04) -+ regmap_update_bits(bmc_device->scu, ASPEED_SCUC24, -+ PCIDEV1_INTX_MSI_HOST2BMC_EN | MSI_ROUTING_MASK, -+ PCIDEV1_INTX_MSI_HOST2BMC_EN | MSI_ROUTING_PCIe2LPC_PCIDEV1); -+ else -+ regmap_update_bits(bmc_device->scu, ASPEED_SCUC24, -+ BIT(17) | BIT(14) | BIT(11), BIT(17) | BIT(14) | BIT(11)); -+#else -+ //SCUC24[18]: Enable PCI device 1 INTx/MSI from Host-to-BMC controller. -+ regmap_update_bits(bmc_device->scu, 0xc24, BIT(18) | BIT(14), BIT(18) | BIT(14)); -+#endif -+ -+ writel((~(bmc_device->bmc_mem_size - 1) & 0xFFFFFFFF) | HOST2BMC_MEM_BAR_ENABLE, -+ bmc_device->reg_base + ASPEED_BMC_MEM_BAR); -+ writel(bmc_device->bmc_mem_phy, bmc_device->reg_base + ASPEED_BMC_MEM_BAR_REMAP); + FUNC_GROUP_DECL(I2C7, D11, E11); ++FUNC_GROUP_DECL(SI2C7, D11, E11); + + #define F13 86 + SIG_EXPR_LIST_DECL_SESG(F13, SCL8, I2C8, SIG_DESC_SET(SCU418, 22)); +-PIN_DECL_1(F13, GPIOK6, SCL8); ++SIG_EXPR_LIST_DECL_SESG(F13, SSCL8, SI2C8, SIG_DESC_SET(SCU4B8, 22)); ++PIN_DECL_2(F13, GPIOK6, SCL8, SSCL8); + + #define E12 87 + SIG_EXPR_LIST_DECL_SESG(E12, SDA8, I2C8, SIG_DESC_SET(SCU418, 23)); +-PIN_DECL_1(E12, GPIOK7, SDA8); ++SIG_EXPR_LIST_DECL_SESG(E12, SSDA8, SI2C8, SIG_DESC_SET(SCU4B8, 23)); ++PIN_DECL_2(E12, GPIOK7, SDA8, SSDA8); + + FUNC_GROUP_DECL(I2C8, F13, E12); ++FUNC_GROUP_DECL(SI2C8, F13, E12); + + #define D15 88 + SIG_EXPR_LIST_DECL_SESG(D15, SCL9, I2C9, SIG_DESC_SET(SCU418, 24)); +-PIN_DECL_1(D15, GPIOL0, SCL9); ++SIG_EXPR_LIST_DECL_SESG(D15, SSCL9, SI2C9, SIG_DESC_SET(SCU4B8, 24)); ++PIN_DECL_2(D15, GPIOL0, SCL9, SSCL9); + + #define A14 89 + SIG_EXPR_LIST_DECL_SESG(A14, SDA9, I2C9, SIG_DESC_SET(SCU418, 25)); +-PIN_DECL_1(A14, GPIOL1, SDA9); ++SIG_EXPR_LIST_DECL_SESG(A14, SSDA9, SI2C9, SIG_DESC_SET(SCU4B8, 25)); ++PIN_DECL_2(A14, GPIOL1, SDA9, SSDA9); + + FUNC_GROUP_DECL(I2C9, D15, A14); ++FUNC_GROUP_DECL(SI2C9, D15, A14); + + #define E15 90 + SIG_EXPR_LIST_DECL_SESG(E15, SCL10, I2C10, SIG_DESC_SET(SCU418, 26)); +-PIN_DECL_1(E15, GPIOL2, SCL10); ++SIG_EXPR_LIST_DECL_SESG(E15, SSCL10, SI2C10, SIG_DESC_SET(SCU4B8, 26)); ++PIN_DECL_2(E15, GPIOL2, SCL10, SSCL10); + + #define A13 91 + SIG_EXPR_LIST_DECL_SESG(A13, SDA10, I2C10, SIG_DESC_SET(SCU418, 27)); +-PIN_DECL_1(A13, GPIOL3, SDA10); ++SIG_EXPR_LIST_DECL_SESG(A13, SSDA10, SI2C10, SIG_DESC_SET(SCU4B8, 27)); ++PIN_DECL_2(A13, GPIOL3, SDA10, SSDA10); + + FUNC_GROUP_DECL(I2C10, E15, A13); ++FUNC_GROUP_DECL(SI2C10, E15, A13); + + #define C15 92 + SSSF_PIN_DECL(C15, GPIOL4, TXD3, SIG_DESC_SET(SCU418, 28)); +@@ -987,9 +1083,8 @@ + + #define AB16 160 + SIG_EXPR_LIST_DECL_SEMG(AB16, SALT9, SALT9G1, SALT9, SIG_DESC_SET(SCU434, 0), +- SIG_DESC_CLEAR(SCU694, 16)); +-SIG_EXPR_LIST_DECL_SESG(AB16, GPIU0, GPIU0, SIG_DESC_SET(SCU434, 0), +- SIG_DESC_SET(SCU694, 16)); ++ SIG_DESC_CLEAR(SCU694, 16), SIG_DESC_SET(SCU4D4, 0)); ++SIG_EXPR_LIST_DECL_SESG(AB16, GPIU0, GPIU0, SIG_DESC_SET(SCU434, 0)); + SIG_EXPR_LIST_DECL_SESG(AB16, ADC8, ADC8); + PIN_DECL_(AB16, SIG_EXPR_LIST_PTR(AB16, SALT9), SIG_EXPR_LIST_PTR(AB16, GPIU0), + SIG_EXPR_LIST_PTR(AB16, ADC8)); +@@ -1000,9 +1095,8 @@ + + #define AA17 161 + SIG_EXPR_LIST_DECL_SEMG(AA17, SALT10, SALT10G1, SALT10, SIG_DESC_SET(SCU434, 1), +- SIG_DESC_CLEAR(SCU694, 17)); +-SIG_EXPR_LIST_DECL_SESG(AA17, GPIU1, GPIU1, SIG_DESC_SET(SCU434, 1), +- SIG_DESC_SET(SCU694, 17)); ++ SIG_DESC_CLEAR(SCU694, 17), SIG_DESC_SET(SCU4D4, 1)); ++SIG_EXPR_LIST_DECL_SESG(AA17, GPIU1, GPIU1, SIG_DESC_SET(SCU434, 1)); + SIG_EXPR_LIST_DECL_SESG(AA17, ADC9, ADC9); + PIN_DECL_(AA17, SIG_EXPR_LIST_PTR(AA17, SALT10), SIG_EXPR_LIST_PTR(AA17, GPIU1), + SIG_EXPR_LIST_PTR(AA17, ADC9)); +@@ -1013,9 +1107,8 @@ + + #define AB17 162 + SIG_EXPR_LIST_DECL_SEMG(AB17, SALT11, SALT11G1, SALT11, SIG_DESC_SET(SCU434, 2), +- SIG_DESC_CLEAR(SCU694, 18)); +-SIG_EXPR_LIST_DECL_SESG(AB17, GPIU2, GPIU2, SIG_DESC_SET(SCU434, 2), +- SIG_DESC_SET(SCU694, 18)); ++ SIG_DESC_CLEAR(SCU694, 18), SIG_DESC_SET(SCU4D4, 2)); ++SIG_EXPR_LIST_DECL_SESG(AB17, GPIU2, GPIU2, SIG_DESC_SET(SCU434, 2)); + SIG_EXPR_LIST_DECL_SESG(AB17, ADC10, ADC10); + PIN_DECL_(AB17, SIG_EXPR_LIST_PTR(AB17, SALT11), SIG_EXPR_LIST_PTR(AB17, GPIU2), + SIG_EXPR_LIST_PTR(AB17, ADC10)); +@@ -1026,9 +1119,8 @@ + + #define AE16 163 + SIG_EXPR_LIST_DECL_SEMG(AE16, SALT12, SALT12G1, SALT12, SIG_DESC_SET(SCU434, 3), +- SIG_DESC_CLEAR(SCU694, 19)); +-SIG_EXPR_LIST_DECL_SESG(AE16, GPIU3, GPIU3, SIG_DESC_SET(SCU434, 3), +- SIG_DESC_SET(SCU694, 19)); ++ SIG_DESC_CLEAR(SCU694, 19), SIG_DESC_SET(SCU4D4, 3)); ++SIG_EXPR_LIST_DECL_SESG(AE16, GPIU3, GPIU3, SIG_DESC_SET(SCU434, 3)); + SIG_EXPR_LIST_DECL_SESG(AE16, ADC11, ADC11); + PIN_DECL_(AE16, SIG_EXPR_LIST_PTR(AE16, SALT12), SIG_EXPR_LIST_PTR(AE16, GPIU3), + SIG_EXPR_LIST_PTR(AE16, ADC11)); +@@ -1039,9 +1131,8 @@ + + #define AC16 164 + SIG_EXPR_LIST_DECL_SEMG(AC16, SALT13, SALT13G1, SALT13, SIG_DESC_SET(SCU434, 4), +- SIG_DESC_CLEAR(SCU694, 20)); +-SIG_EXPR_LIST_DECL_SESG(AC16, GPIU4, GPIU4, SIG_DESC_SET(SCU434, 4), +- SIG_DESC_SET(SCU694, 20)); ++ SIG_DESC_CLEAR(SCU694, 20), SIG_DESC_SET(SCU4D4, 4)); ++SIG_EXPR_LIST_DECL_SESG(AC16, GPIU4, GPIU4, SIG_DESC_SET(SCU434, 4)); + SIG_EXPR_LIST_DECL_SESG(AC16, ADC12, ADC12); + PIN_DECL_(AC16, SIG_EXPR_LIST_PTR(AC16, SALT13), SIG_EXPR_LIST_PTR(AC16, GPIU4), + SIG_EXPR_LIST_PTR(AC16, ADC12)); +@@ -1052,9 +1143,8 @@ + + #define AA16 165 + SIG_EXPR_LIST_DECL_SEMG(AA16, SALT14, SALT14G1, SALT14, SIG_DESC_SET(SCU434, 5), +- SIG_DESC_CLEAR(SCU694, 21)); +-SIG_EXPR_LIST_DECL_SESG(AA16, GPIU5, GPIU5, SIG_DESC_SET(SCU434, 5), +- SIG_DESC_SET(SCU694, 21)); ++ SIG_DESC_CLEAR(SCU694, 21), SIG_DESC_SET(SCU4D4, 5)); ++SIG_EXPR_LIST_DECL_SESG(AA16, GPIU5, GPIU5, SIG_DESC_SET(SCU434, 5)); + SIG_EXPR_LIST_DECL_SESG(AA16, ADC13, ADC13); + PIN_DECL_(AA16, SIG_EXPR_LIST_PTR(AA16, SALT14), SIG_EXPR_LIST_PTR(AA16, GPIU5), + SIG_EXPR_LIST_PTR(AA16, ADC13)); +@@ -1065,9 +1155,8 @@ + + #define AD16 166 + SIG_EXPR_LIST_DECL_SEMG(AD16, SALT15, SALT15G1, SALT15, SIG_DESC_SET(SCU434, 6), +- SIG_DESC_CLEAR(SCU694, 22)); +-SIG_EXPR_LIST_DECL_SESG(AD16, GPIU6, GPIU6, SIG_DESC_SET(SCU434, 6), +- SIG_DESC_SET(SCU694, 22)); ++ SIG_DESC_CLEAR(SCU694, 22), SIG_DESC_SET(SCU4D4, 6)); ++SIG_EXPR_LIST_DECL_SESG(AD16, GPIU6, GPIU6, SIG_DESC_SET(SCU434, 6)); + SIG_EXPR_LIST_DECL_SESG(AD16, ADC14, ADC14); + PIN_DECL_(AD16, SIG_EXPR_LIST_PTR(AD16, SALT15), SIG_EXPR_LIST_PTR(AD16, GPIU6), + SIG_EXPR_LIST_PTR(AD16, ADC14)); +@@ -1078,9 +1167,8 @@ + + #define AC17 167 + SIG_EXPR_LIST_DECL_SEMG(AC17, SALT16, SALT16G1, SALT16, SIG_DESC_SET(SCU434, 7), +- SIG_DESC_CLEAR(SCU694, 23)); +-SIG_EXPR_LIST_DECL_SESG(AC17, GPIU7, GPIU7, SIG_DESC_SET(SCU434, 7), +- SIG_DESC_SET(SCU694, 23)); ++ SIG_DESC_CLEAR(SCU694, 23), SIG_DESC_SET(SCU4D4, 7)); ++SIG_EXPR_LIST_DECL_SESG(AC17, GPIU7, GPIU7, SIG_DESC_SET(SCU434, 7)); + SIG_EXPR_LIST_DECL_SESG(AC17, ADC15, ADC15); + PIN_DECL_(AC17, SIG_EXPR_LIST_PTR(AC17, SALT16), SIG_EXPR_LIST_PTR(AC17, GPIU7), + SIG_EXPR_LIST_PTR(AC17, ADC15)); +@@ -1205,7 +1293,7 @@ + SIG_DESC_SET(SCU4D4, 31)); + PIN_DECL_2(AB10, GPIOX7, SPI2DQ3, RXD12); + +-GROUP_DECL(QSPI2, AE8, AF8, AB9, AD9, AF9, AB10); ++GROUP_DECL(QSPI2, AF9, AB10); + FUNC_DECL_2(SPI2, SPI2, QSPI2); + + GROUP_DECL(UART12G1, AF9, AB10); +@@ -1240,15 +1328,21 @@ + FUNC_GROUP_DECL(WDTRST4, AA12); + + #define AE12 196 ++SIG_EXPR_LIST_DECL_SEMG(AE12, FWSPIDQ2, FWQSPID, FWSPID, ++ SIG_DESC_SET(SCU438, 4)); + SIG_EXPR_LIST_DECL_SESG(AE12, FWSPIQ2, FWQSPI, SIG_DESC_SET(SCU438, 4)); + SIG_EXPR_LIST_DECL_SESG(AE12, GPIOY4, GPIOY4); +-PIN_DECL_(AE12, SIG_EXPR_LIST_PTR(AE12, FWSPIQ2), ++PIN_DECL_(AE12, SIG_EXPR_LIST_PTR(AE12, FWSPIDQ2), ++ SIG_EXPR_LIST_PTR(AE12, FWSPIQ2), + SIG_EXPR_LIST_PTR(AE12, GPIOY4)); + + #define AF12 197 ++SIG_EXPR_LIST_DECL_SEMG(AF12, FWSPIDQ3, FWQSPID, FWSPID, ++ SIG_DESC_SET(SCU438, 5)); + SIG_EXPR_LIST_DECL_SESG(AF12, FWSPIQ3, FWQSPI, SIG_DESC_SET(SCU438, 5)); + SIG_EXPR_LIST_DECL_SESG(AF12, GPIOY5, GPIOY5); +-PIN_DECL_(AF12, SIG_EXPR_LIST_PTR(AF12, FWSPIQ3), ++PIN_DECL_(AF12, SIG_EXPR_LIST_PTR(AF12, FWSPIDQ3), ++ SIG_EXPR_LIST_PTR(AF12, FWSPIQ3), + SIG_EXPR_LIST_PTR(AF12, GPIOY5)); + FUNC_GROUP_DECL(FWQSPI, AE12, AF12); + +@@ -1293,7 +1387,7 @@ + SIG_DESC_CLEAR(SCU4B8, 3), SIG_DESC_SET(SCU4D8, 15)); + PIN_DECL_2(AF10, GPIOZ7, SPI1DQ3, RXD13); + +-GROUP_DECL(QSPI1, AB11, AC11, AA11, AD11, AF10); ++GROUP_DECL(QSPI1, AD11, AF10); + FUNC_DECL_2(SPI1, SPI1, QSPI1); + + GROUP_DECL(UART13G1, AD11, AF10); +@@ -1301,80 +1395,80 @@ + + #define C6 208 + SIG_EXPR_LIST_DECL_SESG(C6, RGMII1TXCK, RGMII1, SIG_DESC_SET(SCU400, 0), +- SIG_DESC_SET(SCU500, 6)); ++ SIG_DESC_SET(SCU500, 6)); + SIG_EXPR_LIST_DECL_SESG(C6, RMII1RCLKO, RMII1, SIG_DESC_SET(SCU400, 0), +- SIG_DESC_CLEAR(SCU500, 6)); ++ SIG_DESC_CLEAR(SCU500, 6)); + PIN_DECL_2(C6, GPIO18A0, RGMII1TXCK, RMII1RCLKO); + + #define D6 209 + SIG_EXPR_LIST_DECL_SESG(D6, RGMII1TXCTL, RGMII1, SIG_DESC_SET(SCU400, 1), +- SIG_DESC_SET(SCU500, 6)); ++ SIG_DESC_SET(SCU500, 6)); + SIG_EXPR_LIST_DECL_SESG(D6, RMII1TXEN, RMII1, SIG_DESC_SET(SCU400, 1), +- SIG_DESC_CLEAR(SCU500, 6)); ++ SIG_DESC_CLEAR(SCU500, 6)); + PIN_DECL_2(D6, GPIO18A1, RGMII1TXCTL, RMII1TXEN); + + #define D5 210 + SIG_EXPR_LIST_DECL_SESG(D5, RGMII1TXD0, RGMII1, SIG_DESC_SET(SCU400, 2), +- SIG_DESC_SET(SCU500, 6)); ++ SIG_DESC_SET(SCU500, 6)); + SIG_EXPR_LIST_DECL_SESG(D5, RMII1TXD0, RMII1, SIG_DESC_SET(SCU400, 2), +- SIG_DESC_CLEAR(SCU500, 6)); ++ SIG_DESC_CLEAR(SCU500, 6)); + PIN_DECL_2(D5, GPIO18A2, RGMII1TXD0, RMII1TXD0); + + #define A3 211 + SIG_EXPR_LIST_DECL_SESG(A3, RGMII1TXD1, RGMII1, SIG_DESC_SET(SCU400, 3), +- SIG_DESC_SET(SCU500, 6)); ++ SIG_DESC_SET(SCU500, 6)); + SIG_EXPR_LIST_DECL_SESG(A3, RMII1TXD1, RMII1, SIG_DESC_SET(SCU400, 3), +- SIG_DESC_CLEAR(SCU500, 6)); ++ SIG_DESC_CLEAR(SCU500, 6)); + PIN_DECL_2(A3, GPIO18A3, RGMII1TXD1, RMII1TXD1); + + #define C5 212 + SIG_EXPR_LIST_DECL_SESG(C5, RGMII1TXD2, RGMII1, SIG_DESC_SET(SCU400, 4), +- SIG_DESC_SET(SCU500, 6)); ++ SIG_DESC_SET(SCU500, 6)); + PIN_DECL_1(C5, GPIO18A4, RGMII1TXD2); + + #define E6 213 + SIG_EXPR_LIST_DECL_SESG(E6, RGMII1TXD3, RGMII1, SIG_DESC_SET(SCU400, 5), +- SIG_DESC_SET(SCU500, 6)); ++ SIG_DESC_SET(SCU500, 6)); + PIN_DECL_1(E6, GPIO18A5, RGMII1TXD3); + + #define B3 214 + SIG_EXPR_LIST_DECL_SESG(B3, RGMII1RXCK, RGMII1, SIG_DESC_SET(SCU400, 6), +- SIG_DESC_SET(SCU500, 6)); ++ SIG_DESC_SET(SCU500, 6)); + SIG_EXPR_LIST_DECL_SESG(B3, RMII1RCLKI, RMII1, SIG_DESC_SET(SCU400, 6), +- SIG_DESC_CLEAR(SCU500, 6)); ++ SIG_DESC_CLEAR(SCU500, 6)); + PIN_DECL_2(B3, GPIO18A6, RGMII1RXCK, RMII1RCLKI); + + #define A2 215 + SIG_EXPR_LIST_DECL_SESG(A2, RGMII1RXCTL, RGMII1, SIG_DESC_SET(SCU400, 7), +- SIG_DESC_SET(SCU500, 6)); ++ SIG_DESC_SET(SCU500, 6)); + PIN_DECL_1(A2, GPIO18A7, RGMII1RXCTL); + + #define B2 216 + SIG_EXPR_LIST_DECL_SESG(B2, RGMII1RXD0, RGMII1, SIG_DESC_SET(SCU400, 8), +- SIG_DESC_SET(SCU500, 6)); ++ SIG_DESC_SET(SCU500, 6)); + SIG_EXPR_LIST_DECL_SESG(B2, RMII1RXD0, RMII1, SIG_DESC_SET(SCU400, 8), +- SIG_DESC_CLEAR(SCU500, 6)); ++ SIG_DESC_CLEAR(SCU500, 6)); + PIN_DECL_2(B2, GPIO18B0, RGMII1RXD0, RMII1RXD0); + + #define B1 217 + SIG_EXPR_LIST_DECL_SESG(B1, RGMII1RXD1, RGMII1, SIG_DESC_SET(SCU400, 9), +- SIG_DESC_SET(SCU500, 6)); ++ SIG_DESC_SET(SCU500, 6)); + SIG_EXPR_LIST_DECL_SESG(B1, RMII1RXD1, RMII1, SIG_DESC_SET(SCU400, 9), +- SIG_DESC_CLEAR(SCU500, 6)); ++ SIG_DESC_CLEAR(SCU500, 6)); + PIN_DECL_2(B1, GPIO18B1, RGMII1RXD1, RMII1RXD1); + + #define C4 218 + SIG_EXPR_LIST_DECL_SESG(C4, RGMII1RXD2, RGMII1, SIG_DESC_SET(SCU400, 10), +- SIG_DESC_SET(SCU500, 6)); ++ SIG_DESC_SET(SCU500, 6)); + SIG_EXPR_LIST_DECL_SESG(C4, RMII1CRSDV, RMII1, SIG_DESC_SET(SCU400, 10), +- SIG_DESC_CLEAR(SCU500, 6)); ++ SIG_DESC_CLEAR(SCU500, 6)); + PIN_DECL_2(C4, GPIO18B2, RGMII1RXD2, RMII1CRSDV); + + #define E5 219 + SIG_EXPR_LIST_DECL_SESG(E5, RGMII1RXD3, RGMII1, SIG_DESC_SET(SCU400, 11), +- SIG_DESC_SET(SCU500, 6)); ++ SIG_DESC_SET(SCU500, 6)); + SIG_EXPR_LIST_DECL_SESG(E5, RMII1RXER, RMII1, SIG_DESC_SET(SCU400, 11), +- SIG_DESC_CLEAR(SCU500, 6)); ++ SIG_DESC_CLEAR(SCU500, 6)); + PIN_DECL_2(E5, GPIO18B3, RGMII1RXD3, RMII1RXER); + + FUNC_GROUP_DECL(RGMII1, C6, D6, D5, A3, C5, E6, B3, A2, B2, B1, C4, E5); +@@ -1382,80 +1476,80 @@ + + #define D4 220 + SIG_EXPR_LIST_DECL_SESG(D4, RGMII2TXCK, RGMII2, SIG_DESC_SET(SCU400, 12), +- SIG_DESC_SET(SCU500, 7)); ++ SIG_DESC_SET(SCU500, 7)); + SIG_EXPR_LIST_DECL_SESG(D4, RMII2RCLKO, RMII2, SIG_DESC_SET(SCU400, 12), +- SIG_DESC_CLEAR(SCU500, 7)); ++ SIG_DESC_CLEAR(SCU500, 7)); + PIN_DECL_2(D4, GPIO18B4, RGMII2TXCK, RMII2RCLKO); + + #define C2 221 + SIG_EXPR_LIST_DECL_SESG(C2, RGMII2TXCTL, RGMII2, SIG_DESC_SET(SCU400, 13), +- SIG_DESC_SET(SCU500, 7)); ++ SIG_DESC_SET(SCU500, 7)); + SIG_EXPR_LIST_DECL_SESG(C2, RMII2TXEN, RMII2, SIG_DESC_SET(SCU400, 13), +- SIG_DESC_CLEAR(SCU500, 7)); ++ SIG_DESC_CLEAR(SCU500, 7)); + PIN_DECL_2(C2, GPIO18B5, RGMII2TXCTL, RMII2TXEN); + + #define C1 222 + SIG_EXPR_LIST_DECL_SESG(C1, RGMII2TXD0, RGMII2, SIG_DESC_SET(SCU400, 14), +- SIG_DESC_SET(SCU500, 7)); ++ SIG_DESC_SET(SCU500, 7)); + SIG_EXPR_LIST_DECL_SESG(C1, RMII2TXD0, RMII2, SIG_DESC_SET(SCU400, 14), +- SIG_DESC_CLEAR(SCU500, 7)); ++ SIG_DESC_CLEAR(SCU500, 7)); + PIN_DECL_2(C1, GPIO18B6, RGMII2TXD0, RMII2TXD0); + + #define D3 223 + SIG_EXPR_LIST_DECL_SESG(D3, RGMII2TXD1, RGMII2, SIG_DESC_SET(SCU400, 15), +- SIG_DESC_SET(SCU500, 7)); ++ SIG_DESC_SET(SCU500, 7)); + SIG_EXPR_LIST_DECL_SESG(D3, RMII2TXD1, RMII2, SIG_DESC_SET(SCU400, 15), +- SIG_DESC_CLEAR(SCU500, 7)); ++ SIG_DESC_CLEAR(SCU500, 7)); + PIN_DECL_2(D3, GPIO18B7, RGMII2TXD1, RMII2TXD1); + + #define E4 224 + SIG_EXPR_LIST_DECL_SESG(E4, RGMII2TXD2, RGMII2, SIG_DESC_SET(SCU400, 16), +- SIG_DESC_SET(SCU500, 7)); ++ SIG_DESC_SET(SCU500, 7)); + PIN_DECL_1(E4, GPIO18C0, RGMII2TXD2); + + #define F5 225 + SIG_EXPR_LIST_DECL_SESG(F5, RGMII2TXD3, RGMII2, SIG_DESC_SET(SCU400, 17), +- SIG_DESC_SET(SCU500, 7)); ++ SIG_DESC_SET(SCU500, 7)); + PIN_DECL_1(F5, GPIO18C1, RGMII2TXD3); + + #define D2 226 + SIG_EXPR_LIST_DECL_SESG(D2, RGMII2RXCK, RGMII2, SIG_DESC_SET(SCU400, 18), +- SIG_DESC_SET(SCU500, 7)); ++ SIG_DESC_SET(SCU500, 7)); + SIG_EXPR_LIST_DECL_SESG(D2, RMII2RCLKI, RMII2, SIG_DESC_SET(SCU400, 18), +- SIG_DESC_CLEAR(SCU500, 7)); ++ SIG_DESC_CLEAR(SCU500, 7)); + PIN_DECL_2(D2, GPIO18C2, RGMII2RXCK, RMII2RCLKI); + + #define E3 227 + SIG_EXPR_LIST_DECL_SESG(E3, RGMII2RXCTL, RGMII2, SIG_DESC_SET(SCU400, 19), +- SIG_DESC_SET(SCU500, 7)); ++ SIG_DESC_SET(SCU500, 7)); + PIN_DECL_1(E3, GPIO18C3, RGMII2RXCTL); + + #define D1 228 + SIG_EXPR_LIST_DECL_SESG(D1, RGMII2RXD0, RGMII2, SIG_DESC_SET(SCU400, 20), +- SIG_DESC_SET(SCU500, 7)); ++ SIG_DESC_SET(SCU500, 7)); + SIG_EXPR_LIST_DECL_SESG(D1, RMII2RXD0, RMII2, SIG_DESC_SET(SCU400, 20), +- SIG_DESC_CLEAR(SCU500, 7)); ++ SIG_DESC_CLEAR(SCU500, 7)); + PIN_DECL_2(D1, GPIO18C4, RGMII2RXD0, RMII2RXD0); + + #define F4 229 + SIG_EXPR_LIST_DECL_SESG(F4, RGMII2RXD1, RGMII2, SIG_DESC_SET(SCU400, 21), +- SIG_DESC_SET(SCU500, 7)); ++ SIG_DESC_SET(SCU500, 7)); + SIG_EXPR_LIST_DECL_SESG(F4, RMII2RXD1, RMII2, SIG_DESC_SET(SCU400, 21), +- SIG_DESC_CLEAR(SCU500, 7)); ++ SIG_DESC_CLEAR(SCU500, 7)); + PIN_DECL_2(F4, GPIO18C5, RGMII2RXD1, RMII2RXD1); + + #define E2 230 + SIG_EXPR_LIST_DECL_SESG(E2, RGMII2RXD2, RGMII2, SIG_DESC_SET(SCU400, 22), +- SIG_DESC_SET(SCU500, 7)); ++ SIG_DESC_SET(SCU500, 7)); + SIG_EXPR_LIST_DECL_SESG(E2, RMII2CRSDV, RMII2, SIG_DESC_SET(SCU400, 22), +- SIG_DESC_CLEAR(SCU500, 7)); ++ SIG_DESC_CLEAR(SCU500, 7)); + PIN_DECL_2(E2, GPIO18C6, RGMII2RXD2, RMII2CRSDV); + + #define E1 231 + SIG_EXPR_LIST_DECL_SESG(E1, RGMII2RXD3, RGMII2, SIG_DESC_SET(SCU400, 23), +- SIG_DESC_SET(SCU500, 7)); ++ SIG_DESC_SET(SCU500, 7)); + SIG_EXPR_LIST_DECL_SESG(E1, RMII2RXER, RMII2, SIG_DESC_SET(SCU400, 23), +- SIG_DESC_CLEAR(SCU500, 7)); ++ SIG_DESC_CLEAR(SCU500, 7)); + PIN_DECL_2(E1, GPIO18C7, RGMII2RXD3, RMII2RXER); + + FUNC_GROUP_DECL(RGMII2, D4, C2, C1, D3, E4, F5, D2, E3, D1, F4, E2, E1); +@@ -1523,8 +1617,9 @@ + PIN_DECL_3(Y4, GPIO18E3, FWSPIDMISO, VBMISO, EMMCDAT7); + + GROUP_DECL(FWSPID, Y1, Y2, Y3, Y4); ++GROUP_DECL(FWQSPID, Y1, Y2, Y3, Y4, AE12, AF12); + GROUP_DECL(EMMCG8, AB4, AA4, AC4, AA5, Y5, AB5, AB6, AC5, Y1, Y2, Y3, Y4); +-FUNC_DECL_1(FWSPID, FWSPID); ++FUNC_DECL_2(FWSPID, FWSPID, FWQSPID); + FUNC_GROUP_DECL(VB, Y1, Y2, Y3, Y4); + FUNC_DECL_3(EMMC, EMMCG1, EMMCG4, EMMCG8); + /* +@@ -1532,13 +1627,15 @@ + * following 4 pins + */ + #define AF25 244 +-SIG_EXPR_LIST_DECL_SEMG(AF25, I3C3SCL, I3C3, I3C3, SIG_DESC_SET(SCU438, 20)); ++SIG_EXPR_LIST_DECL_SEMG(AF25, I3C3SCL, I3C3, I3C3, SIG_DESC_SET(SCU438, 20), ++ SIG_DESC_CLEAR(SCU418, 8)); + SIG_EXPR_LIST_DECL_SESG(AF25, FSI1CLK, FSI1, SIG_DESC_SET(SCU4D8, 20)); + PIN_DECL_(AF25, SIG_EXPR_LIST_PTR(AF25, I3C3SCL), + SIG_EXPR_LIST_PTR(AF25, FSI1CLK)); + + #define AE26 245 +-SIG_EXPR_LIST_DECL_SEMG(AE26, I3C3SDA, I3C3, I3C3, SIG_DESC_SET(SCU438, 21)); ++SIG_EXPR_LIST_DECL_SEMG(AE26, I3C3SDA, I3C3, I3C3, SIG_DESC_SET(SCU438, 21), ++ SIG_DESC_CLEAR(SCU418, 9)); + SIG_EXPR_LIST_DECL_SESG(AE26, FSI1DATA, FSI1, SIG_DESC_SET(SCU4D8, 21)); + PIN_DECL_(AE26, SIG_EXPR_LIST_PTR(AE26, I3C3SDA), + SIG_EXPR_LIST_PTR(AE26, FSI1DATA)); +@@ -1548,13 +1645,15 @@ + FUNC_GROUP_DECL(FSI1, AF25, AE26); + + #define AE25 246 +-SIG_EXPR_LIST_DECL_SEMG(AE25, I3C4SCL, I3C4, I3C4, SIG_DESC_SET(SCU438, 22)); ++SIG_EXPR_LIST_DECL_SEMG(AE25, I3C4SCL, I3C4, I3C4, SIG_DESC_SET(SCU438, 22), ++ SIG_DESC_CLEAR(SCU418, 10)); + SIG_EXPR_LIST_DECL_SESG(AE25, FSI2CLK, FSI2, SIG_DESC_SET(SCU4D8, 22)); + PIN_DECL_(AE25, SIG_EXPR_LIST_PTR(AE25, I3C4SCL), + SIG_EXPR_LIST_PTR(AE25, FSI2CLK)); + + #define AF24 247 +-SIG_EXPR_LIST_DECL_SEMG(AF24, I3C4SDA, I3C4, I3C4, SIG_DESC_SET(SCU438, 23)); ++SIG_EXPR_LIST_DECL_SEMG(AF24, I3C4SDA, I3C4, I3C4, SIG_DESC_SET(SCU438, 23), ++ SIG_DESC_CLEAR(SCU418, 11)); + SIG_EXPR_LIST_DECL_SESG(AF24, FSI2DATA, FSI2, SIG_DESC_SET(SCU4D8, 23)); + PIN_DECL_(AF24, SIG_EXPR_LIST_PTR(AF24, I3C4SDA), + SIG_EXPR_LIST_PTR(AF24, FSI2DATA)); +@@ -1636,6 +1735,23 @@ + FUNC_DECL_1(USB2BD, USBB); + FUNC_DECL_1(USB2BH, USBB); + ++/* bit19: Enable RC-L DMA mode ++ * bit23: Enable RC-L DMA decode ++ */ ++#define PCIERC0_DESC { ASPEED_IP_SCU, SCUC24, GENMASK(23, 19), 0x1f, 0 } + -+ //Setting BMC to Host Q register -+ writel(BMC2HOST_Q2_FULL_UNMASK | BMC2HOST_Q1_FULL_UNMASK | BMC2HOST_ENABLE_INTB, -+ bmc_device->reg_base + ASPEED_BMC_BMC2HOST_STS); -+ writel(HOST2BMC_Q2_FULL_UNMASK | HOST2BMC_Q1_FULL_UNMASK | HOST2BMC_ENABLE_INTB, -+ bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS); ++#define A7 256 ++SIG_EXPR_LIST_DECL_SESG(A7, PERST, PCIERC0, SIG_DESC_SET(SCU040, 21), ++ SIG_DESC_CLEAR(SCU0C8, 6), PCIERC0_DESC); ++PIN_DECL_(A7, SIG_EXPR_LIST_PTR(A7, PERST)); ++FUNC_GROUP_DECL(PCIERC0, A7); + -+ return 0; -+} ++#define D7 257 ++SIG_EXPR_LIST_DECL_SESG(D7, RCRST, PCIERC1, SIG_DESC_SET(SCU040, 19), ++ SIG_DESC_SET(SCU500, 24)); ++PIN_DECL_(D7, SIG_EXPR_LIST_PTR(D7, RCRST)); ++FUNC_GROUP_DECL(PCIERC1, D7); + -+static int aspeed_ast2700_init(struct platform_device *pdev) -+{ -+ struct aspeed_bmc_device *bmc_device = platform_get_drvdata(pdev); -+ struct device *dev = &pdev->dev; -+ u32 pcie_config_ctl; -+ u32 scu_id; -+ int i; + /* Pins, groups and functions are sort(1):ed alphabetically for sanity */ + + static struct pinctrl_pin_desc aspeed_g6_pins[ASPEED_G6_NR_PINS] = { +@@ -1658,6 +1774,7 @@ + ASPEED_PINCTRL_PIN(A3), + ASPEED_PINCTRL_PIN(A4), + ASPEED_PINCTRL_PIN(A6), ++ ASPEED_PINCTRL_PIN(A7), + ASPEED_PINCTRL_PIN(AA11), + ASPEED_PINCTRL_PIN(AA12), + ASPEED_PINCTRL_PIN(AA16), +@@ -1806,6 +1923,7 @@ + ASPEED_PINCTRL_PIN(D4), + ASPEED_PINCTRL_PIN(D5), + ASPEED_PINCTRL_PIN(D6), ++ ASPEED_PINCTRL_PIN(D7), + ASPEED_PINCTRL_PIN(E1), + ASPEED_PINCTRL_PIN(E11), + ASPEED_PINCTRL_PIN(E12), +@@ -1921,6 +2039,7 @@ + ASPEED_PINCTRL_GROUP(FSI2), + ASPEED_PINCTRL_GROUP(FWSPIABR), + ASPEED_PINCTRL_GROUP(FWSPID), ++ ASPEED_PINCTRL_GROUP(FWQSPID), + ASPEED_PINCTRL_GROUP(FWQSPI), + ASPEED_PINCTRL_GROUP(FWSPIWP), + ASPEED_PINCTRL_GROUP(GPIT0), +@@ -1958,6 +2077,16 @@ + ASPEED_PINCTRL_GROUP(I2C7), + ASPEED_PINCTRL_GROUP(I2C8), + ASPEED_PINCTRL_GROUP(I2C9), ++ ASPEED_PINCTRL_GROUP(SI2C1), ++ ASPEED_PINCTRL_GROUP(SI2C2), ++ ASPEED_PINCTRL_GROUP(SI2C3), ++ ASPEED_PINCTRL_GROUP(SI2C4), ++ ASPEED_PINCTRL_GROUP(SI2C5), ++ ASPEED_PINCTRL_GROUP(SI2C6), ++ ASPEED_PINCTRL_GROUP(SI2C7), ++ ASPEED_PINCTRL_GROUP(SI2C8), ++ ASPEED_PINCTRL_GROUP(SI2C9), ++ ASPEED_PINCTRL_GROUP(SI2C10), + ASPEED_PINCTRL_GROUP(I3C1), + ASPEED_PINCTRL_GROUP(I3C2), + ASPEED_PINCTRL_GROUP(I3C3), +@@ -2073,6 +2202,8 @@ + ASPEED_PINCTRL_GROUP(SALT9G1), + ASPEED_PINCTRL_GROUP(SD1), + ASPEED_PINCTRL_GROUP(SD2), ++ ASPEED_PINCTRL_GROUP(PCIERC0), ++ ASPEED_PINCTRL_GROUP(PCIERC1), + ASPEED_PINCTRL_GROUP(EMMCG1), + ASPEED_PINCTRL_GROUP(EMMCG4), + ASPEED_PINCTRL_GROUP(EMMCG8), +@@ -2132,6 +2263,7 @@ + ASPEED_PINCTRL_GROUP(USBA), + ASPEED_PINCTRL_GROUP(USBB), + ASPEED_PINCTRL_GROUP(VB), ++ ASPEED_PINCTRL_GROUP(VPA), + ASPEED_PINCTRL_GROUP(VGAHS), + ASPEED_PINCTRL_GROUP(VGAVS), + ASPEED_PINCTRL_GROUP(WDTRST1), +@@ -2200,6 +2332,16 @@ + ASPEED_PINCTRL_FUNC(I2C7), + ASPEED_PINCTRL_FUNC(I2C8), + ASPEED_PINCTRL_FUNC(I2C9), ++ ASPEED_PINCTRL_FUNC(SI2C1), ++ ASPEED_PINCTRL_FUNC(SI2C2), ++ ASPEED_PINCTRL_FUNC(SI2C3), ++ ASPEED_PINCTRL_FUNC(SI2C4), ++ ASPEED_PINCTRL_FUNC(SI2C5), ++ ASPEED_PINCTRL_FUNC(SI2C6), ++ ASPEED_PINCTRL_FUNC(SI2C7), ++ ASPEED_PINCTRL_FUNC(SI2C8), ++ ASPEED_PINCTRL_FUNC(SI2C9), ++ ASPEED_PINCTRL_FUNC(SI2C10), + ASPEED_PINCTRL_FUNC(I3C1), + ASPEED_PINCTRL_FUNC(I3C2), + ASPEED_PINCTRL_FUNC(I3C3), +@@ -2314,6 +2456,8 @@ + ASPEED_PINCTRL_FUNC(SPI2), + ASPEED_PINCTRL_FUNC(SPI2CS1), + ASPEED_PINCTRL_FUNC(SPI2CS2), ++ ASPEED_PINCTRL_FUNC(PCIERC0), ++ ASPEED_PINCTRL_FUNC(PCIERC1), + ASPEED_PINCTRL_FUNC(TACH0), + ASPEED_PINCTRL_FUNC(TACH1), + ASPEED_PINCTRL_FUNC(TACH10), +@@ -2354,6 +2498,7 @@ + ASPEED_PINCTRL_FUNC(USB2BD), + ASPEED_PINCTRL_FUNC(USB2BH), + ASPEED_PINCTRL_FUNC(VB), ++ ASPEED_PINCTRL_FUNC(VPA), + ASPEED_PINCTRL_FUNC(VGAHS), + ASPEED_PINCTRL_FUNC(VGAVS), + ASPEED_PINCTRL_FUNC(WDTRST1), +@@ -2607,6 +2752,10 @@ + { PIN_CONFIG_DRIVE_STRENGTH, { AB8, AB8 }, SCU454, GENMASK(27, 26)}, + /* LAD0 */ + { PIN_CONFIG_DRIVE_STRENGTH, { AB7, AB7 }, SCU454, GENMASK(25, 24)}, ++ /* GPIOF */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { D22, A23 }, SCU458, GENMASK(9, 8)}, ++ /* GPIOG */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { E21, B21 }, SCU458, GENMASK(11, 10)}, + + /* MAC3 */ + { PIN_CONFIG_POWER_SOURCE, { H24, E26 }, SCU458, BIT_MASK(4)}, +@@ -2615,6 +2764,11 @@ + { PIN_CONFIG_POWER_SOURCE, { F24, B24 }, SCU458, BIT_MASK(5)}, + { PIN_CONFIG_DRIVE_STRENGTH, { F24, B24 }, SCU458, GENMASK(3, 2)}, + ++ /* GPIOJ */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { B20, A20 }, SCU650, BIT_MASK(12)}, ++ { PIN_CONFIG_DRIVE_STRENGTH, { E19, D20 }, SCU650, BIT_MASK(13)}, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C19, A19 }, SCU650, BIT_MASK(14)}, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C20, D19 }, SCU650, BIT_MASK(15)}, + /* GPIO18E */ + ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, Y1, Y4, SCU40C, 4), + 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 @@ ++// SPDX-License-Identifier: GPL-2.0 + -+ bmc_device->device = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,device"); -+ if (IS_ERR(bmc_device->device)) { -+ dev_err(&pdev->dev, "failed to find device regmap\n"); -+ return PTR_ERR(bmc_device->device); -+ } ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "pinctrl-aspeed.h" + -+ bmc_device->e2m = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,e2m"); -+ if (IS_ERR(bmc_device->e2m)) { -+ dev_err(&pdev->dev, "failed to find e2m regmap\n"); -+ return PTR_ERR(bmc_device->e2m); -+ } ++#define SCU3B0 0x3B0 /* USB Controller Register */ ++#define SCU3B4 0x3B4 /* USB Controller Lock Register */ ++#define SCU3B8 0x3B8 /* USB Controller Secure Register #1 */ ++#define SCU3BC 0x3BC /* USB Controller Secure Register #2 */ ++#define SCU3C0 0x3C0 /* USB Controller Secure Register #3 */ ++#define SCU400 0x400 /* Multi-function Pin Control #1 */ ++#define SCU404 0x404 /* Multi-function Pin Control #2 */ ++#define SCU408 0x408 /* Multi-function Pin Control #3 */ ++#define SCU40C 0x40C /* Multi-function Pin Control #4 */ ++#define SCU410 0x410 /* Multi-function Pin Control #5 */ ++#define SCU414 0x414 /* Multi-function Pin Control #6 */ ++#define SCU418 0x418 /* Multi-function Pin Control #7 */ ++#define SCU41C 0x41C /* Multi-function Pin Control #8 */ ++#define SCU420 0x420 /* Multi-function Pin Control #9 */ ++#define SCU424 0x424 /* Multi-function Pin Control #10 */ ++#define SCU428 0x428 /* Multi-function Pin Control #11 */ ++#define SCU42C 0x42C /* Multi-function Pin Control #12 */ ++#define SCU430 0x430 /* Multi-function Pin Control #13 */ ++#define SCU434 0x434 /* Multi-function Pin Control #14 */ ++#define SCU438 0x438 /* Multi-function Pin Control #15 */ ++#define SCU43C 0x43C /* Multi-function Pin Control #16 */ ++#define SCU440 0x440 /* Multi-function Pin Control #17 */ ++#define SCU444 0x444 /* Multi-function Pin Control #18 */ ++#define SCU448 0x448 /* Multi-function Pin Control #19 */ ++#define SCU44C 0x44C /* Multi-function Pin Control #20 */ ++#define SCU450 0x450 /* Multi-function Pin Control #21 */ ++#define SCU454 0x454 /* Multi-function Pin Control #22 */ ++#define SCU458 0x458 /* Multi-function Pin Control #23 */ ++#define SCU45C 0x45C /* Multi-function Pin Control #24 */ ++#define SCU460 0x460 /* Multi-function Pin Control #25 */ ++#define SCU464 0x464 /* Multi-function Pin Control #26 */ ++#define SCU468 0x468 /* Multi-function Pin Control #27 */ ++#define SCU46C 0x46C /* Multi-function Pin Control #28 */ ++#define SCU470 0x470 /* Multi-function Pin Control #29 */ ++#define SCU474 0x474 /* Multi-function Pin Control #30 */ ++#define SCU478 0x478 /* Multi-function Pin Control #31 */ ++#define SCU47C 0x47C ++#define SCU4A0 0x4A0 /* Voltage Selection */ ++#define SCU4C0 0x4C0 /* Driving Strength #0 A-I */ ++#define SCU4C4 0x4C4 /* Driving Strength #1 J-K */ ++#define SCU4C8 0x4C8 /* Driving Strength #2 L-M */ ++#define SCU4CC 0x4CC /* Driving Strength #3 N-O */ ++#define SCU4D0 0x4D0 /* Driving Strength #4 P-Q */ ++#define SCU4D4 0x4D4 /* Driving Strength #5 R-S */ ++#define SCU4D8 0x4D8 /* Driving Strength #6 T-U */ ++#define SCU4DC 0x4DC /* Driving Strength #7 W */ + -+ bmc_device->scu = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,scu"); -+ if (IS_ERR(bmc_device->scu)) { -+ dev_err(&pdev->dev, "failed to find SCU regmap\n"); -+ return PTR_ERR(bmc_device->scu); -+ } ++#define SCU908 0x908 /* PCIe RC PERST Pin Control */ + -+ if (bmc_device->pcie2lpc) { -+ pcie_config_ctl = SCU_PCIE_CONF_BMC_DEV_EN_E2L | -+ SCU_PCIE_CONF_BMC_DEV_EN_LPC_DECODE; -+ regmap_update_bits(bmc_device->scu, SCU0_PCIE_CONF_CTRL, -+ pcie_config_ctl, pcie_config_ctl); -+ } ++enum { ++ D6, ++ B7, ++ A7, ++ C6, ++ B6, ++ A6, ++ C5, ++ D5, ++ L15, ++ H17, ++ L16, ++ K15, ++ K16, ++ K14, ++ J14, ++ J16, ++ J15, ++ G17, ++ F17, ++ D17, ++ C17, ++ H16, ++ B17, ++ E17, ++ A16, ++ B16, ++ H14, ++ A15, ++ G16, ++ F15, ++ H15, ++ D16, ++ M2, ++ M1, ++ M3, ++ M4, ++ N1, ++ N2, ++ N3, ++ L5, ++ P2, ++ P1, ++ N4, ++ N5, ++ HOLE0, ++ P3, ++ R1, ++ P4, ++ J2, ++ J1, ++ K4, ++ K2, ++ K3, ++ K1, ++ L4, ++ L2, ++ L1, ++ L3, ++ A14, ++ B14, ++ HOLE1, ++ HOLE2, ++ HOLE3, ++ HOLE4, ++ U15, ++ U16, ++ T17, ++ P12, ++ R13, ++ T15, ++ T16, ++ R12, ++ R14, ++ R17, ++ R15, ++ P13, ++ R16, ++ P14, ++ P17, ++ P16, ++ P15, ++ N17, ++ N14, ++ M17, ++ N15, ++ N16, ++ L17, ++ K17, ++ J17, ++ M14, ++ M15, ++ M16, ++ A4, ++ B5, ++ A5, ++ B4, ++ A10, ++ B9, ++ C7, ++ E8, ++ E7, ++ B8, ++ A9, ++ A8, ++ HOLE5, ++ HOLE6, ++ HOLE7, ++ HOLE8, ++ HOLE9, ++ HOLE10, ++ HOLE11, ++ HOLE12, ++ E13, ++ C12, ++ D12, ++ E12, ++ D13, ++ HOLE13, ++ B12, ++ HOLE14, ++ D15, ++ B13, ++ C14, ++ C13, ++ D14, ++ F13, ++ E14, ++ HOLE15, ++ HOLE16, ++ HOLE17, ++ B1, ++ C2, ++ D3, ++ C1, ++ E5, ++ HOLE18, ++ C11, ++ D11, ++ HOLE19, ++ HOLE20, ++ C10, ++ D10, ++ HOLE21, ++ HOLE22, ++ HOLE23, ++ HOLE24, ++ D9, ++ E9, ++ C9, ++ D8, ++ C8, ++ B11, ++ B10, ++ A12, ++ A11, ++ D7, ++ HOLE25, ++ HOLE26, ++ HOLE27, ++ HOLE28, ++ G2, ++ G1, ++ G4, ++ H3, ++ H2, ++ H1, ++ J4, ++ J3, ++ C4, ++ A2, ++ C3, ++ B2, ++ B3, ++ A3, ++ F2, ++ F1, ++ D2, ++ D1, ++ F4, ++ E4, ++ E2, ++ E1, ++ F3, ++ G5, ++ T4, ++ T3, ++ R5, ++ R6, ++ T2, ++ T5, ++ U2, ++ R7, ++ P9, ++ U4, ++ U5, ++ U6, ++ T7, ++ U7, ++ R10, ++ R11, ++ C16, ++ F16, ++ B15, ++ G15, ++ G14, ++ F14, ++ E15, ++ C15, ++}; + -+ /* update class code to others as it is a MFD device */ -+ regmap_write(bmc_device->device, 0x18, 0xff000027); ++GROUP_DECL(TACH0, L15); ++GROUP_DECL(TACH1, H17); ++GROUP_DECL(TACH2, L16); ++GROUP_DECL(TACH3, K15); ++GROUP_DECL(TACH4, K16); ++GROUP_DECL(TACH5, K14); ++GROUP_DECL(TACH6, J14); ++GROUP_DECL(TACH7, J16); ++GROUP_DECL(TACH8, J15); ++GROUP_DECL(TACH9, G17); ++GROUP_DECL(TACH10, F17); ++GROUP_DECL(TACH11, D17); ++GROUP_DECL(TACH12, C17); ++GROUP_DECL(TACH13, H16); ++GROUP_DECL(TACH14, B17); ++GROUP_DECL(TACH15, E17); ++GROUP_DECL(PWM0, A16); ++GROUP_DECL(PWM1, B16); ++GROUP_DECL(PWM2, H14); ++GROUP_DECL(PWM3, A15); ++GROUP_DECL(PWM4, G16); ++GROUP_DECL(PWM5, F15); ++GROUP_DECL(PWM6, H15); ++GROUP_DECL(PWM7, D16); ++GROUP_DECL(PWM8, K4); ++GROUP_DECL(PWM9, K2); ++GROUP_DECL(PWM10, K3); ++GROUP_DECL(PWM11, K1); ++GROUP_DECL(PWM12, L4); ++GROUP_DECL(PWM13, L2); ++GROUP_DECL(PWM14, L1); ++GROUP_DECL(PWM15, L3); ++GROUP_DECL(ADC0, T4); ++GROUP_DECL(ADC1, T3); ++GROUP_DECL(ADC2, R5); ++GROUP_DECL(ADC3, R6); ++GROUP_DECL(ADC4, T2); ++GROUP_DECL(ADC5, T5); ++GROUP_DECL(ADC6, U2); ++GROUP_DECL(ADC7, R7); ++GROUP_DECL(ADC8, P9); ++GROUP_DECL(ADC9, U4); ++GROUP_DECL(ADC10, U5); ++GROUP_DECL(ADC11, U6); ++GROUP_DECL(ADC12, T7); ++GROUP_DECL(ADC13, U7); ++GROUP_DECL(ADC14, R10); ++GROUP_DECL(ADC15, R11); ++GROUP_DECL(SGPM1, F14, E15, A14, B14); ++GROUP_DECL(I2C0, G2, G1); ++GROUP_DECL(I2C1, G4, H3); ++GROUP_DECL(I2C2, H2, H1); ++GROUP_DECL(I2C3, J4, J3); ++GROUP_DECL(I2C4, C4, A2); ++GROUP_DECL(I2C5, C3, B2); ++GROUP_DECL(I2C6, B3, A3); ++GROUP_DECL(I2C7, F2, F1); ++GROUP_DECL(I2C8, D2, D1); ++GROUP_DECL(I2C9, F4, E4); ++GROUP_DECL(I2C10, E2, E1); ++GROUP_DECL(I2C11, F3, G5); ++GROUP_DECL(I2C12, J1, K2); ++GROUP_DECL(I2C13, K3, K1); ++GROUP_DECL(I2C14, L4, L2); ++GROUP_DECL(I2C15, L1, L3); ++GROUP_DECL(HVI3C12, U15, U16); ++GROUP_DECL(HVI3C13, T17, P12); ++GROUP_DECL(HVI3C14, R13, T15); ++GROUP_DECL(HVI3C15, T16, R12); ++GROUP_DECL(I3C4, R14, R17); ++GROUP_DECL(I3C5, R15, P13); ++GROUP_DECL(I3C6, R16, P14); ++GROUP_DECL(I3C7, P17, P16); ++GROUP_DECL(I3C8, P15, N17); ++GROUP_DECL(I3C9, N14, M17); ++GROUP_DECL(I3C10, N15, N16); ++GROUP_DECL(I3C11, L17, K17); ++GROUP_DECL(HVI3C0, J17, M14); ++GROUP_DECL(HVI3C1, M15, M16); ++GROUP_DECL(HVI3C2, A4, B5); ++GROUP_DECL(HVI3C3, A5, B4); ++GROUP_DECL(JTAGM, C2, D3, C1, E5); + -+ /* MSI */ -+ regmap_update_bits(bmc_device->device, 0x74, GENMASK(7, 4), BIT(7) | (5 << 4)); -+ /* EnPCIaMSI:BIT(25), EnPCIaIntA:BIT(17), EnPCIaMst:BIT(9), EnPCIaDev:BIT(1) */ -+ regmap_read(bmc_device->scu, SCU0_REVISION_ID, &scu_id); -+ if (scu_id & REVISION_ID) -+ regmap_update_bits(bmc_device->device, 0x70, -+ BIT(25) | BIT(17) | BIT(9) | BIT(1), -+ BIT(25) | BIT(17) | BIT(9) | BIT(1)); -+ else -+ /* Disable MSI[bit25] in ast2700A0 int only */ -+ regmap_update_bits(bmc_device->device, 0x70, -+ BIT(17) | BIT(9) | BIT(1), -+ BIT(25) | BIT(17) | BIT(9) | BIT(1)); ++static struct aspeed_pin_group aspeed_g7_ltpi_pingroups[] = { ++ ASPEED_PINCTRL_GROUP(TACH0), ++ ASPEED_PINCTRL_GROUP(TACH1), ++ ASPEED_PINCTRL_GROUP(TACH2), ++ ASPEED_PINCTRL_GROUP(TACH3), ++ ASPEED_PINCTRL_GROUP(TACH4), ++ ASPEED_PINCTRL_GROUP(TACH5), ++ ASPEED_PINCTRL_GROUP(TACH6), ++ ASPEED_PINCTRL_GROUP(TACH7), ++ ASPEED_PINCTRL_GROUP(TACH8), ++ ASPEED_PINCTRL_GROUP(TACH9), ++ ASPEED_PINCTRL_GROUP(TACH10), ++ ASPEED_PINCTRL_GROUP(TACH11), ++ ASPEED_PINCTRL_GROUP(TACH12), ++ ASPEED_PINCTRL_GROUP(TACH13), ++ ASPEED_PINCTRL_GROUP(TACH14), ++ ASPEED_PINCTRL_GROUP(TACH15), ++ ASPEED_PINCTRL_GROUP(PWM0), ++ ASPEED_PINCTRL_GROUP(PWM1), ++ ASPEED_PINCTRL_GROUP(PWM2), ++ ASPEED_PINCTRL_GROUP(PWM3), ++ ASPEED_PINCTRL_GROUP(PWM4), ++ ASPEED_PINCTRL_GROUP(PWM5), ++ ASPEED_PINCTRL_GROUP(PWM6), ++ ASPEED_PINCTRL_GROUP(PWM7), ++ ASPEED_PINCTRL_GROUP(PWM8), ++ ASPEED_PINCTRL_GROUP(PWM9), ++ ASPEED_PINCTRL_GROUP(PWM10), ++ ASPEED_PINCTRL_GROUP(PWM11), ++ ASPEED_PINCTRL_GROUP(PWM12), ++ ASPEED_PINCTRL_GROUP(PWM13), ++ ASPEED_PINCTRL_GROUP(PWM14), ++ ASPEED_PINCTRL_GROUP(PWM15), ++ ASPEED_PINCTRL_GROUP(ADC0), ++ ASPEED_PINCTRL_GROUP(ADC1), ++ ASPEED_PINCTRL_GROUP(ADC2), ++ ASPEED_PINCTRL_GROUP(ADC3), ++ ASPEED_PINCTRL_GROUP(ADC4), ++ ASPEED_PINCTRL_GROUP(ADC5), ++ ASPEED_PINCTRL_GROUP(ADC6), ++ ASPEED_PINCTRL_GROUP(ADC7), ++ ASPEED_PINCTRL_GROUP(ADC8), ++ ASPEED_PINCTRL_GROUP(ADC9), ++ ASPEED_PINCTRL_GROUP(ADC10), ++ ASPEED_PINCTRL_GROUP(ADC11), ++ ASPEED_PINCTRL_GROUP(ADC12), ++ ASPEED_PINCTRL_GROUP(ADC13), ++ ASPEED_PINCTRL_GROUP(ADC14), ++ ASPEED_PINCTRL_GROUP(ADC15), ++ ASPEED_PINCTRL_GROUP(I2C0), ++ ASPEED_PINCTRL_GROUP(I2C1), ++ ASPEED_PINCTRL_GROUP(I2C2), ++ ASPEED_PINCTRL_GROUP(I2C3), ++ ASPEED_PINCTRL_GROUP(I2C4), ++ ASPEED_PINCTRL_GROUP(I2C5), ++ ASPEED_PINCTRL_GROUP(I2C6), ++ ASPEED_PINCTRL_GROUP(I2C7), ++ ASPEED_PINCTRL_GROUP(I2C8), ++ ASPEED_PINCTRL_GROUP(I2C9), ++ ASPEED_PINCTRL_GROUP(I2C10), ++ ASPEED_PINCTRL_GROUP(I2C11), ++ ASPEED_PINCTRL_GROUP(I2C12), ++ ASPEED_PINCTRL_GROUP(I2C13), ++ ASPEED_PINCTRL_GROUP(I2C14), ++ ASPEED_PINCTRL_GROUP(I2C15), ++ ASPEED_PINCTRL_GROUP(HVI3C12), ++ ASPEED_PINCTRL_GROUP(HVI3C13), ++ ASPEED_PINCTRL_GROUP(HVI3C14), ++ ASPEED_PINCTRL_GROUP(HVI3C15), ++ ASPEED_PINCTRL_GROUP(I3C4), ++ ASPEED_PINCTRL_GROUP(I3C5), ++ ASPEED_PINCTRL_GROUP(I3C6), ++ ASPEED_PINCTRL_GROUP(I3C7), ++ ASPEED_PINCTRL_GROUP(I3C8), ++ ASPEED_PINCTRL_GROUP(I3C9), ++ ASPEED_PINCTRL_GROUP(I3C10), ++ ASPEED_PINCTRL_GROUP(I3C11), ++ ASPEED_PINCTRL_GROUP(HVI3C0), ++ ASPEED_PINCTRL_GROUP(HVI3C1), ++ ASPEED_PINCTRL_GROUP(HVI3C2), ++ ASPEED_PINCTRL_GROUP(HVI3C3), ++ ASPEED_PINCTRL_GROUP(JTAGM), ++ ASPEED_PINCTRL_GROUP(SGPM1), ++}; + -+ /* bar size check for 4k align */ -+ for (i = 1; i < 16; i++) { -+ if ((bmc_device->bmc_mem_size / 4096) == (1 << (i - 1))) -+ break; -+ } -+ if (i == 16) { -+ i = 0; -+ dev_warn(bmc_device->dev, -+ "Bar size not align for 4K : %dK\n", (u32)bmc_device->bmc_mem_size / 1024); -+ } ++FUNC_DECL_(TACH0, "TACH0"); ++FUNC_DECL_(TACH1, "TACH1"); ++FUNC_DECL_(TACH2, "TACH2"); ++FUNC_DECL_(TACH3, "TACH3"); ++FUNC_DECL_(TACH4, "TACH4"); ++FUNC_DECL_(TACH5, "TACH5"); ++FUNC_DECL_(TACH6, "TACH6"); ++FUNC_DECL_(TACH7, "TACH7"); ++FUNC_DECL_(TACH8, "TACH8"); ++FUNC_DECL_(TACH9, "TACH9"); ++FUNC_DECL_(TACH10, "TACH10"); ++FUNC_DECL_(TACH11, "TACH11"); ++FUNC_DECL_(TACH12, "TACH12"); ++FUNC_DECL_(TACH13, "TACH13"); ++FUNC_DECL_(TACH14, "TACH14"); ++FUNC_DECL_(TACH15, "TACH15"); ++FUNC_DECL_(PWM0, "PWM0"); ++FUNC_DECL_(PWM1, "PWM1"); ++FUNC_DECL_(PWM2, "PWM2"); ++FUNC_DECL_(PWM3, "PWM3"); ++FUNC_DECL_(PWM4, "PWM4"); ++FUNC_DECL_(PWM5, "PWM5"); ++FUNC_DECL_(PWM6, "PWM6"); ++FUNC_DECL_(PWM7, "PWM7"); ++FUNC_DECL_(PWM8, "PWM8"); ++FUNC_DECL_(PWM9, "PWM9"); ++FUNC_DECL_(PWM10, "PWM10"); ++FUNC_DECL_(PWM11, "PWM11"); ++FUNC_DECL_(PWM12, "PWM12"); ++FUNC_DECL_(PWM13, "PWM13"); ++FUNC_DECL_(PWM14, "PWM14"); ++FUNC_DECL_(PWM15, "PWM15"); ++FUNC_DECL_(ADC0, "ADC0"); ++FUNC_DECL_(ADC1, "ADC1"); ++FUNC_DECL_(ADC2, "ADC2"); ++FUNC_DECL_(ADC3, "ADC3"); ++FUNC_DECL_(ADC4, "ADC4"); ++FUNC_DECL_(ADC5, "ADC5"); ++FUNC_DECL_(ADC6, "ADC6"); ++FUNC_DECL_(ADC7, "ADC7"); ++FUNC_DECL_(ADC8, "ADC8"); ++FUNC_DECL_(ADC9, "ADC9"); ++FUNC_DECL_(ADC10, "ADC10"); ++FUNC_DECL_(ADC11, "ADC11"); ++FUNC_DECL_(ADC12, "ADC12"); ++FUNC_DECL_(ADC13, "ADC13"); ++FUNC_DECL_(ADC14, "ADC14"); ++FUNC_DECL_(ADC15, "ADC15"); ++FUNC_DECL_(I2C0, "I2C0"); ++FUNC_DECL_(I2C1, "I2C1"); ++FUNC_DECL_(I2C2, "I2C2"); ++FUNC_DECL_(I2C3, "I2C3"); ++FUNC_DECL_(I2C4, "I2C4"); ++FUNC_DECL_(I2C5, "I2C5"); ++FUNC_DECL_(I2C6, "I2C6"); ++FUNC_DECL_(I2C7, "I2C7"); ++FUNC_DECL_(I2C8, "I2C8"); ++FUNC_DECL_(I2C9, "I2C9"); ++FUNC_DECL_(I2C10, "I2C10"); ++FUNC_DECL_(I2C11, "I2C11"); ++FUNC_DECL_(I2C12, "I2C12"); ++FUNC_DECL_(I2C13, "I2C13"); ++FUNC_DECL_(I2C14, "I2C14"); ++FUNC_DECL_(I2C15, "I2C15"); ++FUNC_DECL_(I3C12, "HVI3C12"); ++FUNC_DECL_(I3C13, "HVI3C13"); ++FUNC_DECL_(I3C14, "HVI3C14"); ++FUNC_DECL_(I3C15, "HVI3C15"); ++FUNC_DECL_(I3C4, "I3C4"); ++FUNC_DECL_(I3C5, "I3C5"); ++FUNC_DECL_(I3C6, "I3C6"); ++FUNC_DECL_(I3C7, "I3C7"); ++FUNC_DECL_(I3C8, "I3C8"); ++FUNC_DECL_(I3C9, "I3C9"); ++FUNC_DECL_(I3C10, "I3C10"); ++FUNC_DECL_(I3C11, "I3C11"); ++FUNC_DECL_(I3C0, "HVI3C0"); ++FUNC_DECL_(I3C1, "HVI3C1"); ++FUNC_DECL_(I3C2, "HVI3C2"); ++FUNC_DECL_(I3C3, "HVI3C3"); ++FUNC_DECL_(JTAGM, "JTAGM"); ++FUNC_DECL_(SGPM1, "SGPM1"); + -+ /* -+ * BAR assign in scu -+ * ((bar_mem / 4k) << 8) | per_size -+ */ -+ regmap_write(bmc_device->device, 0x1c, ((bmc_device->bmc_mem_phy) >> 4) | i); ++static struct aspeed_pin_function aspeed_g7_ltpi_funcs[] = { ++ ASPEED_PINCTRL_FUNC(TACH0), ++ ASPEED_PINCTRL_FUNC(TACH1), ++ ASPEED_PINCTRL_FUNC(TACH2), ++ ASPEED_PINCTRL_FUNC(TACH3), ++ ASPEED_PINCTRL_FUNC(TACH4), ++ ASPEED_PINCTRL_FUNC(TACH5), ++ ASPEED_PINCTRL_FUNC(TACH6), ++ ASPEED_PINCTRL_FUNC(TACH7), ++ ASPEED_PINCTRL_FUNC(TACH8), ++ ASPEED_PINCTRL_FUNC(TACH9), ++ ASPEED_PINCTRL_FUNC(TACH10), ++ ASPEED_PINCTRL_FUNC(TACH11), ++ ASPEED_PINCTRL_FUNC(TACH12), ++ ASPEED_PINCTRL_FUNC(TACH13), ++ ASPEED_PINCTRL_FUNC(TACH14), ++ ASPEED_PINCTRL_FUNC(TACH15), ++ ASPEED_PINCTRL_FUNC(PWM0), ++ ASPEED_PINCTRL_FUNC(PWM1), ++ ASPEED_PINCTRL_FUNC(PWM2), ++ ASPEED_PINCTRL_FUNC(PWM3), ++ ASPEED_PINCTRL_FUNC(PWM4), ++ ASPEED_PINCTRL_FUNC(PWM5), ++ ASPEED_PINCTRL_FUNC(PWM6), ++ ASPEED_PINCTRL_FUNC(PWM7), ++ ASPEED_PINCTRL_FUNC(PWM8), ++ ASPEED_PINCTRL_FUNC(PWM9), ++ ASPEED_PINCTRL_FUNC(PWM10), ++ ASPEED_PINCTRL_FUNC(PWM11), ++ ASPEED_PINCTRL_FUNC(PWM12), ++ ASPEED_PINCTRL_FUNC(PWM13), ++ ASPEED_PINCTRL_FUNC(PWM14), ++ ASPEED_PINCTRL_FUNC(PWM15), ++ ASPEED_PINCTRL_FUNC(ADC0), ++ ASPEED_PINCTRL_FUNC(ADC1), ++ ASPEED_PINCTRL_FUNC(ADC2), ++ ASPEED_PINCTRL_FUNC(ADC3), ++ ASPEED_PINCTRL_FUNC(ADC4), ++ ASPEED_PINCTRL_FUNC(ADC5), ++ ASPEED_PINCTRL_FUNC(ADC6), ++ ASPEED_PINCTRL_FUNC(ADC7), ++ ASPEED_PINCTRL_FUNC(ADC8), ++ ASPEED_PINCTRL_FUNC(ADC9), ++ ASPEED_PINCTRL_FUNC(ADC10), ++ ASPEED_PINCTRL_FUNC(ADC11), ++ ASPEED_PINCTRL_FUNC(ADC12), ++ ASPEED_PINCTRL_FUNC(ADC13), ++ ASPEED_PINCTRL_FUNC(ADC14), ++ ASPEED_PINCTRL_FUNC(ADC15), ++ ASPEED_PINCTRL_FUNC(I2C0), ++ ASPEED_PINCTRL_FUNC(I2C1), ++ ASPEED_PINCTRL_FUNC(I2C2), ++ ASPEED_PINCTRL_FUNC(I2C3), ++ ASPEED_PINCTRL_FUNC(I2C4), ++ ASPEED_PINCTRL_FUNC(I2C5), ++ ASPEED_PINCTRL_FUNC(I2C6), ++ ASPEED_PINCTRL_FUNC(I2C7), ++ ASPEED_PINCTRL_FUNC(I2C8), ++ ASPEED_PINCTRL_FUNC(I2C9), ++ ASPEED_PINCTRL_FUNC(I2C10), ++ ASPEED_PINCTRL_FUNC(I2C11), ++ ASPEED_PINCTRL_FUNC(I2C12), ++ ASPEED_PINCTRL_FUNC(I2C13), ++ ASPEED_PINCTRL_FUNC(I2C14), ++ ASPEED_PINCTRL_FUNC(I2C15), ++ ASPEED_PINCTRL_FUNC(I3C12), ++ ASPEED_PINCTRL_FUNC(I3C13), ++ ASPEED_PINCTRL_FUNC(I3C14), ++ ASPEED_PINCTRL_FUNC(I3C15), ++ ASPEED_PINCTRL_FUNC(I3C4), ++ ASPEED_PINCTRL_FUNC(I3C5), ++ ASPEED_PINCTRL_FUNC(I3C6), ++ ASPEED_PINCTRL_FUNC(I3C7), ++ ASPEED_PINCTRL_FUNC(I3C8), ++ ASPEED_PINCTRL_FUNC(I3C9), ++ ASPEED_PINCTRL_FUNC(I3C10), ++ ASPEED_PINCTRL_FUNC(I3C11), ++ ASPEED_PINCTRL_FUNC(I3C0), ++ ASPEED_PINCTRL_FUNC(I3C1), ++ ASPEED_PINCTRL_FUNC(I3C2), ++ ASPEED_PINCTRL_FUNC(I3C3), ++ ASPEED_PINCTRL_FUNC(JTAGM), ++ ASPEED_PINCTRL_FUNC(SGPM1), ++}; + -+ if (bmc_device->id == 0) -+ /* Node 0 Bar 0 */ -+ regmap_write(bmc_device->e2m, 0x108, ((bmc_device->bmc_mem_phy) >> 4) | i); -+ else -+ /* Node 1 Bar 0 */ -+ regmap_write(bmc_device->e2m, 0x128, ((bmc_device->bmc_mem_phy) >> 4) | i); ++/* number, name, drv_data */ ++static const struct pinctrl_pin_desc aspeed_g7_ltpi_pins[] = { ++ PINCTRL_PIN(D6, "D6"), ++ PINCTRL_PIN(B7, "B7"), ++ PINCTRL_PIN(A7, "A7"), ++ PINCTRL_PIN(C6, "C6"), ++ PINCTRL_PIN(B6, "B6"), ++ PINCTRL_PIN(A6, "A6"), ++ PINCTRL_PIN(C5, "C5"), ++ PINCTRL_PIN(D5, "D5"), ++ PINCTRL_PIN(L15, "L15"), ++ PINCTRL_PIN(H17, "H17"), ++ PINCTRL_PIN(L16, "L16"), ++ PINCTRL_PIN(K15, "K15"), ++ PINCTRL_PIN(K16, "K16"), ++ PINCTRL_PIN(K14, "K14"), ++ PINCTRL_PIN(J14, "J14"), ++ PINCTRL_PIN(J16, "J16"), ++ PINCTRL_PIN(J15, "J15"), ++ PINCTRL_PIN(G17, "G17"), ++ PINCTRL_PIN(F17, "F17"), ++ PINCTRL_PIN(D17, "D17"), ++ PINCTRL_PIN(C17, "C17"), ++ PINCTRL_PIN(H16, "H16"), ++ PINCTRL_PIN(B17, "B17"), ++ PINCTRL_PIN(E17, "E17"), ++ PINCTRL_PIN(A16, "A16"), ++ PINCTRL_PIN(B16, "B16"), ++ PINCTRL_PIN(H14, "H14"), ++ PINCTRL_PIN(A15, "A15"), ++ PINCTRL_PIN(G16, "G16"), ++ PINCTRL_PIN(F15, "F15"), ++ PINCTRL_PIN(H15, "H15"), ++ PINCTRL_PIN(D16, "D16"), ++ PINCTRL_PIN(M2, "M2"), ++ PINCTRL_PIN(M1, "M1"), ++ PINCTRL_PIN(M3, "M3"), ++ PINCTRL_PIN(M4, "M4"), ++ PINCTRL_PIN(N1, "N1"), ++ PINCTRL_PIN(N2, "N2"), ++ PINCTRL_PIN(N3, "N3"), ++ PINCTRL_PIN(L5, "L5"), ++ PINCTRL_PIN(P2, "P2"), ++ PINCTRL_PIN(P1, "P1"), ++ PINCTRL_PIN(N4, "N4"), ++ PINCTRL_PIN(N5, "N5"), ++ PINCTRL_PIN(HOLE0, "HOLE0"), ++ PINCTRL_PIN(P3, "P3"), ++ PINCTRL_PIN(R1, "R1"), ++ PINCTRL_PIN(P4, "P4"), ++ PINCTRL_PIN(J2, "J2"), ++ PINCTRL_PIN(J1, "J1"), ++ PINCTRL_PIN(K4, "K4"), ++ PINCTRL_PIN(K2, "K2"), ++ PINCTRL_PIN(K3, "K3"), ++ PINCTRL_PIN(K1, "K1"), ++ PINCTRL_PIN(L4, "L4"), ++ PINCTRL_PIN(L2, "L2"), ++ PINCTRL_PIN(L1, "L1"), ++ PINCTRL_PIN(L3, "L3"), ++ PINCTRL_PIN(A14, "A14"), ++ PINCTRL_PIN(B14, "B14"), ++ PINCTRL_PIN(HOLE1, "HOLE1"), ++ PINCTRL_PIN(HOLE2, "HOLE2"), ++ PINCTRL_PIN(HOLE3, "HOLE3"), ++ PINCTRL_PIN(HOLE4, "HOLE4"), ++ PINCTRL_PIN(U15, "U15"), ++ PINCTRL_PIN(U16, "U16"), ++ PINCTRL_PIN(T17, "T17"), ++ PINCTRL_PIN(P12, "P12"), ++ PINCTRL_PIN(R13, "R13"), ++ PINCTRL_PIN(T15, "T15"), ++ PINCTRL_PIN(T16, "T16"), ++ PINCTRL_PIN(R12, "R12"), ++ PINCTRL_PIN(R14, "R14"), ++ PINCTRL_PIN(R17, "R17"), ++ PINCTRL_PIN(R15, "R15"), ++ PINCTRL_PIN(P13, "P13"), ++ PINCTRL_PIN(R16, "R16"), ++ PINCTRL_PIN(P14, "P14"), ++ PINCTRL_PIN(P17, "P17"), ++ PINCTRL_PIN(P16, "P16"), ++ PINCTRL_PIN(P15, "P15"), ++ PINCTRL_PIN(N17, "N17"), ++ PINCTRL_PIN(N14, "N14"), ++ PINCTRL_PIN(M17, "M17"), ++ PINCTRL_PIN(N15, "N15"), ++ PINCTRL_PIN(N16, "N16"), ++ PINCTRL_PIN(L17, "L17"), ++ PINCTRL_PIN(K17, "K17"), ++ PINCTRL_PIN(J17, "J17"), ++ PINCTRL_PIN(M14, "M14"), ++ PINCTRL_PIN(M15, "M15"), ++ PINCTRL_PIN(M16, "M16"), ++ PINCTRL_PIN(A4, "A4"), ++ PINCTRL_PIN(B5, "B5"), ++ PINCTRL_PIN(A5, "A5"), ++ PINCTRL_PIN(B4, "B4"), ++ PINCTRL_PIN(A10, "A10"), ++ PINCTRL_PIN(B9, "B9"), ++ PINCTRL_PIN(C7, "C7"), ++ PINCTRL_PIN(E8, "E8"), ++ PINCTRL_PIN(E7, "E7"), ++ PINCTRL_PIN(B8, "B8"), ++ PINCTRL_PIN(A9, "A9"), ++ PINCTRL_PIN(A8, "A8"), ++ PINCTRL_PIN(HOLE5, "HOLE5"), ++ PINCTRL_PIN(HOLE6, "HOLE6"), ++ PINCTRL_PIN(HOLE7, "HOLE7"), ++ PINCTRL_PIN(HOLE8, "HOLE8"), ++ PINCTRL_PIN(HOLE9, "HOLE9"), ++ PINCTRL_PIN(HOLE10, "HOLE10"), ++ PINCTRL_PIN(HOLE11, "HOLE11"), ++ PINCTRL_PIN(HOLE12, "HOLE12"), ++ PINCTRL_PIN(E13, "E13"), ++ PINCTRL_PIN(C12, "C12"), ++ PINCTRL_PIN(D12, "D12"), ++ PINCTRL_PIN(E12, "E12"), ++ PINCTRL_PIN(D13, "D13"), ++ PINCTRL_PIN(HOLE13, "HOLE13"), ++ PINCTRL_PIN(B12, "B12"), ++ PINCTRL_PIN(HOLE14, "HOLE14"), ++ PINCTRL_PIN(D15, "D15"), ++ PINCTRL_PIN(B13, "B13"), ++ PINCTRL_PIN(C14, "C14"), ++ PINCTRL_PIN(C13, "C13"), ++ PINCTRL_PIN(D14, "D14"), ++ PINCTRL_PIN(F13, "F13"), ++ PINCTRL_PIN(E14, "E14"), ++ PINCTRL_PIN(HOLE15, "HOLE15"), ++ PINCTRL_PIN(HOLE16, "HOLE16"), ++ PINCTRL_PIN(HOLE17, "HOLE17"), ++ PINCTRL_PIN(B1, "B1"), ++ PINCTRL_PIN(C2, "C2"), ++ PINCTRL_PIN(D3, "D3"), ++ 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(D9, "D9"), ++ PINCTRL_PIN(E9, "E9"), ++ PINCTRL_PIN(C9, "C9"), ++ PINCTRL_PIN(D8, "D8"), ++ PINCTRL_PIN(C8, "C8"), ++ PINCTRL_PIN(B11, "B11"), ++ PINCTRL_PIN(B10, "B10"), ++ 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(G2, "G2"), ++ PINCTRL_PIN(G1, "G1"), ++ PINCTRL_PIN(G4, "G4"), ++ PINCTRL_PIN(H3, "H3"), ++ PINCTRL_PIN(H2, "H2"), ++ PINCTRL_PIN(H1, "H1"), ++ PINCTRL_PIN(J4, "J4"), ++ PINCTRL_PIN(J3, "J3"), ++ PINCTRL_PIN(C4, "C4"), ++ PINCTRL_PIN(A2, "A2"), ++ PINCTRL_PIN(C3, "C3"), ++ PINCTRL_PIN(B2, "B2"), ++ PINCTRL_PIN(B3, "B3"), ++ PINCTRL_PIN(A3, "A3"), ++ PINCTRL_PIN(F2, "F2"), ++ PINCTRL_PIN(F1, "F1"), ++ PINCTRL_PIN(D2, "D2"), ++ PINCTRL_PIN(D1, "D1"), ++ PINCTRL_PIN(F4, "F4"), ++ PINCTRL_PIN(E4, "E4"), ++ PINCTRL_PIN(E2, "E2"), ++ PINCTRL_PIN(E1, "E1"), ++ PINCTRL_PIN(F3, "F3"), ++ PINCTRL_PIN(G5, "G5"), ++ PINCTRL_PIN(T4, "T4"), ++ PINCTRL_PIN(T3, "T3"), ++ PINCTRL_PIN(R5, "R5"), ++ PINCTRL_PIN(R6, "R6"), ++ PINCTRL_PIN(T2, "T2"), ++ PINCTRL_PIN(T5, "T5"), ++ PINCTRL_PIN(U2, "U2"), ++ PINCTRL_PIN(R7, "R7"), ++ PINCTRL_PIN(P9, "P9"), ++ PINCTRL_PIN(U4, "U4"), ++ PINCTRL_PIN(U5, "U5"), ++ PINCTRL_PIN(U6, "U6"), ++ PINCTRL_PIN(T7, "T7"), ++ PINCTRL_PIN(U7, "U7"), ++ PINCTRL_PIN(R10, "R10"), ++ PINCTRL_PIN(R11, "R11"), ++ PINCTRL_PIN(C16, "C16"), ++ PINCTRL_PIN(F16, "F16"), ++ PINCTRL_PIN(B15, "B15"), ++ PINCTRL_PIN(G15, "G15"), ++ PINCTRL_PIN(G14, "G14"), ++ PINCTRL_PIN(F14, "F14"), ++ PINCTRL_PIN(E15, "E15"), ++ PINCTRL_PIN(C15, "C15"), ++}; + -+ /* Setting BMC to Host Q register */ -+ writel(BMC2HOST_Q2_FULL_UNMASK | BMC2HOST_Q1_FULL_UNMASK | BMC2HOST_ENABLE_INTB, -+ bmc_device->reg_base + ASPEED_BMC_BMC2HOST_STS); -+ writel(HOST2BMC_Q2_FULL_UNMASK | HOST2BMC_Q1_FULL_UNMASK | HOST2BMC_ENABLE_INTB, -+ bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS); ++FUNCFG_DESCL(L15, PIN_CFG(TACH0, SCU404, GENMASK(2, 0), 1)); ++FUNCFG_DESCL(H17, PIN_CFG(TACH1, SCU404, GENMASK(6, 4), (1 << 4))); ++FUNCFG_DESCL(L16, PIN_CFG(TACH2, SCU404, GENMASK(10, 8), (1 << 8))); ++FUNCFG_DESCL(K15, PIN_CFG(TACH3, SCU404, GENMASK(14, 12), (1 << 12))); ++FUNCFG_DESCL(K16, PIN_CFG(TACH4, SCU404, GENMASK(18, 16), (1 << 16))); ++FUNCFG_DESCL(K14, PIN_CFG(TACH5, SCU404, GENMASK(22, 20), (1 << 20))); ++FUNCFG_DESCL(J14, PIN_CFG(TACH6, SCU404, GENMASK(26, 24), (1 << 24))); ++FUNCFG_DESCL(J16, PIN_CFG(TACH7, SCU404, GENMASK(30, 28), (1 << 28))); ++FUNCFG_DESCL(J15, PIN_CFG(TACH8, SCU408, GENMASK(2, 0), 1)); ++FUNCFG_DESCL(G17, PIN_CFG(TACH9, SCU408, GENMASK(6, 4), (1 << 4))); ++FUNCFG_DESCL(F17, PIN_CFG(TACH10, SCU408, GENMASK(10, 8), (1 << 8))); ++FUNCFG_DESCL(D17, PIN_CFG(TACH11, SCU408, GENMASK(14, 12), (1 << 12))); ++FUNCFG_DESCL(C17, PIN_CFG(TACH12, SCU408, GENMASK(18, 16), (1 << 16))); ++FUNCFG_DESCL(H16, PIN_CFG(TACH13, SCU408, GENMASK(22, 20), (1 << 20))); ++FUNCFG_DESCL(B17, PIN_CFG(TACH14, SCU408, GENMASK(26, 24), (1 << 24))); ++FUNCFG_DESCL(E17, PIN_CFG(TACH15, SCU408, GENMASK(30, 28), (1 << 28))); ++FUNCFG_DESCL(A16, PIN_CFG(PWM0, SCU40C, GENMASK(2, 0), 1)); ++FUNCFG_DESCL(B16, PIN_CFG(PWM1, SCU40C, GENMASK(6, 4), (1 << 4))); ++FUNCFG_DESCL(H14, PIN_CFG(PWM2, SCU40C, GENMASK(10, 8), (1 << 8))); ++FUNCFG_DESCL(A15, PIN_CFG(PWM3, SCU40C, GENMASK(14, 12), (1 << 12))); ++FUNCFG_DESCL(G16, PIN_CFG(PWM4, SCU40C, GENMASK(18, 16), (1 << 16))); ++FUNCFG_DESCL(F15, PIN_CFG(PWM5, SCU40C, GENMASK(22, 20), (1 << 20))); ++FUNCFG_DESCL(H15, PIN_CFG(PWM6, SCU40C, GENMASK(26, 24), (1 << 24))); ++FUNCFG_DESCL(D16, PIN_CFG(PWM7, SCU40C, GENMASK(30, 28), (1 << 28))); ++FUNCFG_DESCL(J1, PIN_CFG(I2C12, SCU418, GENMASK(6, 4), (4 << 4))); ++FUNCFG_DESCL(K4, PIN_CFG(PWM8, SCU418, GENMASK(10, 8), (3 << 8))); ++FUNCFG_DESCL(K2, PIN_CFG(PWM9, SCU418, GENMASK(14, 12), (3 << 12)), ++ PIN_CFG(I2C12, SCU418, GENMASK(14, 12), (4 << 12))); ++FUNCFG_DESCL(K3, PIN_CFG(PWM10, SCU418, GENMASK(18, 16), (3 << 16)), ++ PIN_CFG(I2C13, SCU418, GENMASK(18, 16), (4 << 16))); ++FUNCFG_DESCL(K1, PIN_CFG(PWM11, SCU418, GENMASK(22, 20), (3 << 20)), ++ PIN_CFG(I2C13, SCU418, GENMASK(22, 20), (4 << 20))); ++FUNCFG_DESCL(L4, PIN_CFG(PWM12, SCU418, GENMASK(26, 24), (3 << 24)), ++ PIN_CFG(I2C14, SCU418, GENMASK(26, 24), (4 << 24))); ++FUNCFG_DESCL(L2, PIN_CFG(PWM13, SCU418, GENMASK(30, 28), (3 << 28)), ++ PIN_CFG(I2C14, SCU418, GENMASK(30, 28), (4 << 28))); ++FUNCFG_DESCL(L1, PIN_CFG(I2C15, SCU41C, GENMASK(2, 0), 2), ++ PIN_CFG(PWM14, SCU41C, GENMASK(2, 0), 3)); ++FUNCFG_DESCL(L3, PIN_CFG(I2C15, SCU41C, GENMASK(6, 4), (2 << 4)), ++ PIN_CFG(PWM15, SCU41C, GENMASK(6, 4), (3 << 4))); ++FUNCFG_DESCL(A14, PIN_CFG(SGPM1, SCU41C, GENMASK(10, 8), (1 << 8))); ++FUNCFG_DESCL(B14, PIN_CFG(SGPM1, SCU41C, GENMASK(14, 12), (1 << 12))); ++FUNCFG_DESCL(U15, PIN_CFG(HVI3C12, SCU420, GENMASK(2, 0), 1)); ++FUNCFG_DESCL(U16, PIN_CFG(HVI3C12, SCU420, GENMASK(6, 4), (1 << 4))); ++FUNCFG_DESCL(T17, PIN_CFG(HVI3C13, SCU420, GENMASK(10, 8), (1 << 8))); ++FUNCFG_DESCL(P12, PIN_CFG(HVI3C13, SCU420, GENMASK(14, 12), (1 << 12))); ++FUNCFG_DESCL(R13, PIN_CFG(HVI3C14, SCU420, GENMASK(18, 16), (1 << 16))); ++FUNCFG_DESCL(T15, PIN_CFG(HVI3C14, SCU420, GENMASK(22, 20), (1 << 20))); ++FUNCFG_DESCL(T16, PIN_CFG(HVI3C15, SCU420, GENMASK(26, 24), (1 << 24))); ++FUNCFG_DESCL(R12, PIN_CFG(HVI3C15, SCU420, GENMASK(30, 28), (1 << 28))); ++FUNCFG_DESCL(R14, PIN_CFG(I3C4, SCU424, GENMASK(2, 0), 1)); ++FUNCFG_DESCL(R17, PIN_CFG(I3C4, SCU424, GENMASK(6, 4), (1 << 4))); ++FUNCFG_DESCL(R15, PIN_CFG(I3C5, SCU424, GENMASK(10, 8), (1 << 8))); ++FUNCFG_DESCL(P13, PIN_CFG(I3C5, SCU424, GENMASK(14, 12), (1 << 12))); ++FUNCFG_DESCL(R16, PIN_CFG(I3C6, SCU424, GENMASK(18, 16), (1 << 16))); ++FUNCFG_DESCL(P14, PIN_CFG(I3C6, SCU424, GENMASK(22, 20), (1 << 20))); ++FUNCFG_DESCL(P17, PIN_CFG(I3C7, SCU424, GENMASK(26, 24), (1 << 24))); ++FUNCFG_DESCL(P16, PIN_CFG(I3C7, SCU424, GENMASK(30, 28), (1 << 28))); ++FUNCFG_DESCL(P15, PIN_CFG(I3C8, SCU428, GENMASK(2, 0), 1)); ++FUNCFG_DESCL(N17, PIN_CFG(I3C8, SCU428, GENMASK(6, 4), (1 << 4))); ++FUNCFG_DESCL(N14, PIN_CFG(I3C9, SCU428, GENMASK(10, 8), (1 << 8))); ++FUNCFG_DESCL(M17, PIN_CFG(I3C9, SCU428, GENMASK(14, 12), (1 << 12))); ++FUNCFG_DESCL(N15, PIN_CFG(I3C10, SCU428, GENMASK(18, 16), (1 << 16))); ++FUNCFG_DESCL(N16, PIN_CFG(I3C10, SCU428, GENMASK(22, 20), (1 << 20))); ++FUNCFG_DESCL(L17, PIN_CFG(I3C11, SCU428, GENMASK(26, 24), (1 << 24))); ++FUNCFG_DESCL(K17, PIN_CFG(I3C11, SCU428, GENMASK(30, 28), (1 << 28))); ++FUNCFG_DESCL(J17, PIN_CFG(HVI3C0, SCU42C, GENMASK(2, 0), 1)); ++FUNCFG_DESCL(M14, PIN_CFG(HVI3C0, SCU42C, GENMASK(6, 4), (1 << 4))); ++FUNCFG_DESCL(M15, PIN_CFG(HVI3C1, SCU42C, GENMASK(10, 8), (1 << 8))); ++FUNCFG_DESCL(M16, PIN_CFG(HVI3C1, SCU42C, GENMASK(14, 12), (1 << 12))); ++FUNCFG_DESCL(A4, PIN_CFG(HVI3C2, SCU42C, GENMASK(18, 16), (1 << 16))); ++FUNCFG_DESCL(B5, PIN_CFG(HVI3C2, SCU42C, GENMASK(22, 20), (1 << 20))); ++FUNCFG_DESCL(A5, PIN_CFG(HVI3C3, SCU42C, GENMASK(26, 24), (1 << 24))); ++FUNCFG_DESCL(B4, PIN_CFG(HVI3C3, SCU42C, GENMASK(30, 28), (1 << 28))); ++FUNCFG_DESCL(C2, PIN_CFG(JTAGM, SCU440, GENMASK(14, 12), (1 << 12))); ++FUNCFG_DESCL(D3, PIN_CFG(JTAGM, SCU440, GENMASK(18, 16), (1 << 16))); ++FUNCFG_DESCL(C1, PIN_CFG(JTAGM, SCU440, GENMASK(22, 20), (1 << 20))); ++FUNCFG_DESCL(E5, PIN_CFG(JTAGM, SCU440, GENMASK(26, 24), (1 << 24))); ++FUNCFG_DESCL(G2, PIN_CFG(I2C0, SCU454, GENMASK(2, 0), 1)); ++FUNCFG_DESCL(G1, PIN_CFG(I2C0, SCU454, GENMASK(6, 4), (1 << 4))); ++FUNCFG_DESCL(G4, PIN_CFG(I2C1, SCU454, GENMASK(10, 8), (1 << 8))); ++FUNCFG_DESCL(H3, PIN_CFG(I2C1, SCU454, GENMASK(14, 12), (1 << 12))); ++FUNCFG_DESCL(H2, PIN_CFG(I2C2, SCU454, GENMASK(18, 16), (1 << 16))); ++FUNCFG_DESCL(H1, PIN_CFG(I2C2, SCU454, GENMASK(22, 20), (1 << 20))); ++FUNCFG_DESCL(J4, PIN_CFG(I2C3, SCU454, GENMASK(26, 24), (1 << 24))); ++FUNCFG_DESCL(J3, PIN_CFG(I2C3, SCU454, GENMASK(30, 28), (1 << 28))); ++FUNCFG_DESCL(C4, PIN_CFG(I2C4, SCU458, GENMASK(2, 0), 1)); ++FUNCFG_DESCL(A2, PIN_CFG(I2C4, SCU458, GENMASK(6, 4), (1 << 4))); ++FUNCFG_DESCL(C3, PIN_CFG(I2C5, SCU458, GENMASK(10, 8), (1 << 8))); ++FUNCFG_DESCL(B2, PIN_CFG(I2C5, SCU458, GENMASK(14, 12), (1 << 12))); ++FUNCFG_DESCL(B3, PIN_CFG(I2C6, SCU458, GENMASK(18, 16), (1 << 16))); ++FUNCFG_DESCL(A3, PIN_CFG(I2C6, SCU458, GENMASK(22, 20), (1 << 20))); ++FUNCFG_DESCL(F2, PIN_CFG(I2C7, SCU458, GENMASK(26, 24), (1 << 24))); ++FUNCFG_DESCL(F1, PIN_CFG(I2C7, SCU458, GENMASK(30, 28), (1 << 28))); ++FUNCFG_DESCL(D2, PIN_CFG(I2C8, SCU45C, GENMASK(2, 0), 1)); ++FUNCFG_DESCL(D1, PIN_CFG(I2C8, SCU45C, GENMASK(6, 4), (1 << 4))); ++FUNCFG_DESCL(F4, PIN_CFG(I2C9, SCU45C, GENMASK(10, 8), (1 << 8))); ++FUNCFG_DESCL(E4, PIN_CFG(I2C9, SCU45C, GENMASK(14, 12), (1 << 12))); ++FUNCFG_DESCL(E2, PIN_CFG(I2C10, SCU45C, GENMASK(18, 16), (1 << 16))); ++FUNCFG_DESCL(E1, PIN_CFG(I2C10, SCU45C, GENMASK(22, 20), (1 << 20))); ++FUNCFG_DESCL(F3, PIN_CFG(I2C11, SCU45C, GENMASK(26, 24), (1 << 24))); ++FUNCFG_DESCL(G5, PIN_CFG(I2C11, SCU45C, GENMASK(30, 28), (1 << 28))); ++FUNCFG_DESCL(T4, PIN_CFG(ADC0, SCU460, GENMASK(2, 0), 0)); ++FUNCFG_DESCL(T3, PIN_CFG(ADC1, SCU460, GENMASK(6, 4), 0)); ++FUNCFG_DESCL(R5, PIN_CFG(ADC2, SCU460, GENMASK(10, 8), 0)); ++FUNCFG_DESCL(R6, PIN_CFG(ADC3, SCU460, GENMASK(14, 12), 0)); ++FUNCFG_DESCL(T2, PIN_CFG(ADC4, SCU460, GENMASK(18, 16), 0)); ++FUNCFG_DESCL(T5, PIN_CFG(ADC5, SCU460, GENMASK(22, 20), 0)); ++FUNCFG_DESCL(U2, PIN_CFG(ADC6, SCU460, GENMASK(26, 24), 0)); ++FUNCFG_DESCL(R7, PIN_CFG(ADC7, SCU460, GENMASK(30, 28), 0)); ++FUNCFG_DESCL(P9, PIN_CFG(ADC8, SCU464, GENMASK(2, 0), 0)); ++FUNCFG_DESCL(U4, PIN_CFG(ADC9, SCU464, GENMASK(6, 4), 0)); ++FUNCFG_DESCL(U5, PIN_CFG(ADC10, SCU464, GENMASK(10, 8), 0)); ++FUNCFG_DESCL(U6, PIN_CFG(ADC11, SCU464, GENMASK(14, 12), 0)); ++FUNCFG_DESCL(T7, PIN_CFG(ADC12, SCU464, GENMASK(18, 16), 0)); ++FUNCFG_DESCL(U7, PIN_CFG(ADC13, SCU464, GENMASK(22, 20), 0)); ++FUNCFG_DESCL(R10, PIN_CFG(ADC14, SCU464, GENMASK(26, 24), 0)); ++FUNCFG_DESCL(R11, PIN_CFG(ADC15, SCU464, GENMASK(30, 28), 0)); ++FUNCFG_DESCL(F14, PIN_CFG(SGPM1, SCU468, GENMASK(22, 20), (1 << 20))); ++FUNCFG_DESCL(E15, PIN_CFG(SGPM1, SCU468, GENMASK(26, 24), (1 << 24))); + -+ return 0; -+} ++static const struct aspeed_g7_pincfg pin_cfg[] = { ++ PINCFG_PIN(L15), ++ PINCFG_PIN(H17), ++ PINCFG_PIN(L16), ++ PINCFG_PIN(K15), ++ PINCFG_PIN(K16), ++ PINCFG_PIN(K14), ++ PINCFG_PIN(J14), ++ PINCFG_PIN(J16), ++ PINCFG_PIN(J15), ++ PINCFG_PIN(G17), ++ PINCFG_PIN(F17), ++ PINCFG_PIN(D17), ++ PINCFG_PIN(C17), ++ PINCFG_PIN(H16), ++ PINCFG_PIN(B17), ++ PINCFG_PIN(E17), ++ PINCFG_PIN(A16), ++ PINCFG_PIN(B16), ++ PINCFG_PIN(H14), ++ PINCFG_PIN(A15), ++ PINCFG_PIN(G16), ++ PINCFG_PIN(F15), ++ PINCFG_PIN(H15), ++ PINCFG_PIN(D16), ++ PINCFG_PIN(J1), ++ PINCFG_PIN(K4), ++ PINCFG_PIN(K2), ++ PINCFG_PIN(K3), ++ PINCFG_PIN(K1), ++ PINCFG_PIN(L4), ++ PINCFG_PIN(L2), ++ PINCFG_PIN(L1), ++ PINCFG_PIN(L3), ++ PINCFG_PIN(A14), ++ PINCFG_PIN(B14), ++ PINCFG_PIN(U15), ++ PINCFG_PIN(U16), ++ PINCFG_PIN(T17), ++ PINCFG_PIN(P12), ++ PINCFG_PIN(R13), ++ PINCFG_PIN(T15), ++ PINCFG_PIN(T16), ++ PINCFG_PIN(R12), ++ PINCFG_PIN(R14), ++ PINCFG_PIN(R17), ++ PINCFG_PIN(R15), ++ PINCFG_PIN(P13), ++ PINCFG_PIN(R16), ++ PINCFG_PIN(P14), ++ PINCFG_PIN(P17), ++ PINCFG_PIN(P16), ++ PINCFG_PIN(P15), ++ PINCFG_PIN(N17), ++ PINCFG_PIN(N14), ++ PINCFG_PIN(M17), ++ PINCFG_PIN(N15), ++ PINCFG_PIN(N16), ++ PINCFG_PIN(L17), ++ PINCFG_PIN(K17), ++ PINCFG_PIN(J17), ++ PINCFG_PIN(M14), ++ PINCFG_PIN(M15), ++ PINCFG_PIN(M16), ++ PINCFG_PIN(A4), ++ PINCFG_PIN(B5), ++ PINCFG_PIN(A5), ++ PINCFG_PIN(B4), ++ PINCFG_PIN(C2), ++ PINCFG_PIN(D3), ++ PINCFG_PIN(C1), ++ PINCFG_PIN(E5), ++ PINCFG_PIN(G2), ++ PINCFG_PIN(G1), ++ PINCFG_PIN(G4), ++ PINCFG_PIN(H3), ++ PINCFG_PIN(H2), ++ PINCFG_PIN(H1), ++ PINCFG_PIN(J4), ++ PINCFG_PIN(J3), ++ PINCFG_PIN(C4), ++ PINCFG_PIN(A2), ++ PINCFG_PIN(C3), ++ PINCFG_PIN(B2), ++ PINCFG_PIN(B3), ++ PINCFG_PIN(A3), ++ PINCFG_PIN(F2), ++ PINCFG_PIN(F1), ++ PINCFG_PIN(D2), ++ PINCFG_PIN(D1), ++ PINCFG_PIN(F4), ++ PINCFG_PIN(E4), ++ PINCFG_PIN(E2), ++ PINCFG_PIN(E1), ++ PINCFG_PIN(F3), ++ PINCFG_PIN(G5), ++ PINCFG_PIN(T4), ++ PINCFG_PIN(T3), ++ PINCFG_PIN(R5), ++ PINCFG_PIN(R6), ++ PINCFG_PIN(T2), ++ PINCFG_PIN(T5), ++ PINCFG_PIN(U2), ++ PINCFG_PIN(R7), ++ PINCFG_PIN(P9), ++ PINCFG_PIN(U4), ++ PINCFG_PIN(U5), ++ PINCFG_PIN(U6), ++ PINCFG_PIN(T7), ++ PINCFG_PIN(U7), ++ PINCFG_PIN(R10), ++ PINCFG_PIN(R11), ++ PINCFG_PIN(F14), ++ PINCFG_PIN(E15), ++}; + -+static int aspeed_bmc_device_setup_queue(struct platform_device *pdev) ++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) +{ -+ struct aspeed_bmc_device *bmc_device = platform_get_drvdata(pdev); -+ struct device *dev = &pdev->dev; -+ int ret, i; -+ -+ for (i = 0; i < ASPEED_QUEUE_NUM; i++) { -+ struct aspeed_queue_message *queue = &bmc_device->queue[i]; -+ -+ init_waitqueue_head(&queue->tx_wait); -+ init_waitqueue_head(&queue->rx_wait); -+ -+ sysfs_bin_attr_init(&queue->bin); -+ -+ /* Queue name index starts from 1 */ -+ queue->bin.attr.name = -+ devm_kasprintf(dev, GFP_KERNEL, "bmc-dev-queue%d", (i + 1)); -+ queue->bin.attr.mode = 0600; -+ queue->bin.read = bmc_device->platform->queue_rx; -+ queue->bin.write = bmc_device->platform->queue_tx; -+ queue->bin.size = 4; -+ queue->bin.private = queue; -+ -+ ret = sysfs_create_bin_file(&pdev->dev.kobj, &queue->bin); -+ if (ret) { -+ dev_err(dev, "error for bin%d file\n", i); -+ return ret; -+ } -+ -+ queue->kn = kernfs_find_and_get(dev->kobj.sd, queue->bin.attr.name); -+ if (!queue->kn) { -+ sysfs_remove_bin_file(&dev->kobj, &queue->bin); -+ return ret; -+ } -+ -+ queue->index = i; -+ queue->bmc_device = bmc_device; -+ } -+ -+ return 0; ++ return pinconf_generic_dt_node_to_map(pctldev, np_config, map, num_maps, ++ PIN_MAP_TYPE_INVALID); +} + -+static int aspeed_bmc_device_setup_memory_mapping(struct platform_device *pdev) ++static void aspeed_g7_ltpi_dt_free_map(struct pinctrl_dev *pctldev, ++ struct pinctrl_map *map, u32 num_maps) +{ -+ struct aspeed_bmc_device *bmc_device = platform_get_drvdata(pdev); -+ struct device *dev = &pdev->dev; -+ int ret; -+ -+ bmc_device->miscdev.minor = MISC_DYNAMIC_MINOR; -+ bmc_device->miscdev.name = devm_kasprintf(dev, GFP_KERNEL, "bmc-device%d", bmc_device->id); -+ bmc_device->miscdev.fops = &aspeed_bmc_device_fops; -+ bmc_device->miscdev.parent = dev; -+ ret = misc_register(&bmc_device->miscdev); -+ if (ret) { -+ dev_err(dev, "Unable to register device\n"); -+ return ret; -+ } -+ -+ return 0; ++ kfree(map); +} + -+static struct aspeed_platform ast2600_plaform = { -+ .init = aspeed_ast2600_init, -+ .queue_rx = aspeed_ast2600_queue_rx, -+ .queue_tx = aspeed_ast2600_queue_tx ++static const struct pinctrl_ops aspeed_g7_ltpi_pinctrl_ops = { ++ .get_groups_count = aspeed_pinctrl_get_groups_count, ++ .get_group_name = aspeed_pinctrl_get_group_name, ++ .get_group_pins = aspeed_pinctrl_get_group_pins, ++ .pin_dbg_show = aspeed_pinctrl_pin_dbg_show, ++ .dt_node_to_map = aspeed_g7_ltpi_dt_node_to_map, ++ .dt_free_map = aspeed_g7_ltpi_dt_free_map, +}; + -+static struct aspeed_platform ast2700_plaform = { -+ .init = aspeed_ast2700_init, -+ .queue_rx = aspeed_ast2700_queue_rx, -+ .queue_tx = aspeed_ast2700_queue_tx ++static const struct pinmux_ops aspeed_g7_ltpi_pinmux_ops = { ++ .get_functions_count = aspeed_pinmux_get_fn_count, ++ .get_function_name = aspeed_pinmux_get_fn_name, ++ .get_function_groups = aspeed_pinmux_get_fn_groups, ++ .set_mux = aspeed_g7_pinmux_set_mux, ++ .gpio_request_enable = aspeed_g7_gpio_request_enable, ++ .strict = true, +}; + -+static const struct of_device_id aspeed_bmc_device_of_matches[] = { -+ { .compatible = "aspeed,ast2600-bmc-device", .data = &ast2600_plaform }, -+ { .compatible = "aspeed,ast2700-bmc-device", .data = &ast2700_plaform }, -+ {}, ++static const struct pinconf_ops aspeed_g7_ltpi_pinconf_ops = { ++ .is_generic = true, ++ .pin_config_get = aspeed_pin_config_get, ++ .pin_config_set = aspeed_pin_config_set, ++ .pin_config_group_get = aspeed_pin_config_group_get, ++ .pin_config_group_set = aspeed_pin_config_group_set, +}; -+MODULE_DEVICE_TABLE(of, aspeed_bmc_device_of_matches); -+ -+static int aspeed_bmc_device_probe(struct platform_device *pdev) -+{ -+ struct aspeed_bmc_device *bmc_device; -+ struct device *dev = &pdev->dev; -+ struct resource res; -+ const void *md = of_device_get_match_data(dev); -+ struct device_node *np; -+ int ret = 0, i; -+ -+ if (!md) -+ return -ENODEV; -+ -+ bmc_device = devm_kzalloc(&pdev->dev, sizeof(struct aspeed_bmc_device), GFP_KERNEL); -+ if (!bmc_device) -+ return -ENOMEM; -+ dev_set_drvdata(dev, bmc_device); -+ -+ bmc_device->platform = md; -+ -+ bmc_device->id = of_alias_get_id(dev->of_node, "bmcdev"); -+ if (bmc_device->id < 0) -+ bmc_device->id = 0; -+ -+ bmc_device->dev = dev; -+ bmc_device->reg_base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(bmc_device->reg_base)) -+ 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"); -+ 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"); -+ return -ENOMEM; -+ } ++/* pinctrl_desc */ ++static struct pinctrl_desc aspeed_g7_ltpi_pinctrl_desc = { ++ .name = "aspeed-g7-ltpi-pinctrl", ++ .pins = aspeed_g7_ltpi_pins, ++ .npins = ARRAY_SIZE(aspeed_g7_ltpi_pins), ++ .pctlops = &aspeed_g7_ltpi_pinctrl_ops, ++ .pmxops = &aspeed_g7_ltpi_pinmux_ops, ++ .confops = &aspeed_g7_ltpi_pinconf_ops, ++ .owner = THIS_MODULE, ++}; + -+ of_node_put(np); ++static int aspeed_g7_ltpi_pinctrl_probe(struct platform_device *pdev) ++{ ++ struct aspeed_pinctrl_data *ltpi_pinctrl_data; + -+ 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"); ++ ltpi_pinctrl_data = devm_kzalloc(&pdev->dev, sizeof(*ltpi_pinctrl_data), ++ GFP_KERNEL); ++ if (!ltpi_pinctrl_data) + 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); -+ return bmc_device->irq; -+ } ++ ltpi_pinctrl_data->pins = aspeed_g7_ltpi_pins; ++ ltpi_pinctrl_data->npins = ARRAY_SIZE(aspeed_g7_ltpi_pins); ++ ltpi_pinctrl_data->pinmux.groups = aspeed_g7_ltpi_pingroups; ++ ltpi_pinctrl_data->pinmux.ngroups = ARRAY_SIZE(aspeed_g7_ltpi_pingroups); ++ ltpi_pinctrl_data->pinmux.functions = aspeed_g7_ltpi_funcs; ++ 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); + -+ 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"); -+ return ret; -+ } ++ return aspeed_pinctrl_probe(pdev, &aspeed_g7_ltpi_pinctrl_desc, ltpi_pinctrl_data); ++} + -+ ret = aspeed_bmc_device_setup_queue(pdev); -+ if (ret) { -+ dev_err(dev, "Cannot setup queue message"); -+ goto out; -+ } ++static const struct of_device_id aspeed_g7_ltpi_pinctrl_match[] = { ++ { .compatible = "aspeed,ast1700-pinctrl" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, aspeed_g7_ltpi_pinctrl_match); + -+ ret = aspeed_bmc_device_setup_memory_mapping(pdev); -+ if (ret) { -+ dev_err(dev, "Cannot setup memory mapping misc"); -+ goto out_free_queue; -+ } ++static struct platform_driver aspeed_g7_ltpi_pinctrl_driver = { ++ .probe = aspeed_g7_ltpi_pinctrl_probe, ++ .driver = { ++ .name = "aspeed-g7-ltpi-pinctrl", ++ .of_match_table = aspeed_g7_ltpi_pinctrl_match, ++ .suppress_bind_attrs = true, ++ }, ++}; + -+ if (of_property_read_bool(dev->of_node, "pcie2lpc")) -+ bmc_device->pcie2lpc = 1; ++static int __init aspeed_g7_ltpi_pinctrl_register(void) ++{ ++ return platform_driver_register(&aspeed_g7_ltpi_pinctrl_driver); ++} ++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 +@@ -0,0 +1,503 @@ ++// SPDX-License-Identifier: GPL-2.0 + -+ ret = bmc_device->platform->init(pdev); -+ if (ret) { -+ dev_err(dev, "Initialize bmc device failed\n"); -+ goto out_free_misc; -+ } ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "pinctrl-aspeed.h" ++#include "../pinctrl-utils.h" + -+ bmc_device->pcie_irq = platform_get_irq(pdev, 1); -+ if (bmc_device->pcie_irq < 0) { -+ dev_warn(&pdev->dev, -+ "platform get of pcie irq[=%d] failed!\n", bmc_device->pcie_irq); -+ } else { -+ ret = devm_request_irq(&pdev->dev, bmc_device->pcie_irq, -+ aspeed_bmc_dev_pcie_isr, IRQF_SHARED, -+ dev_name(&pdev->dev), bmc_device); -+ if (ret < 0) { -+ dev_warn(dev, "Failed to request PCI-E IRQ %d.\n", ret); -+ bmc_device->pcie_irq = -1; -+ } -+ } ++#define SCU200 0x200 /* System Reset Control #1 */ + -+ dev_info(dev, "aspeed bmc device: driver successfully loaded.\n"); ++#define SCU400 0x400 /* Multi-function Pin Control #1 */ ++#define SCU404 0x404 /* Multi-function Pin Control #2 */ ++#define SCU408 0x408 /* Multi-function Pin Control #3 */ ++#define SCU40C 0x40C /* Multi-function Pin Control #3 */ ++#define SCU410 0x410 /* USB Multi-function Control Register */ ++#define SCU414 0x414 /* VGA Function Control Register */ + -+ return 0; ++#define SCU480 0x480 /* GPIO18A0 IO Control Register */ ++#define SCU484 0x484 /* GPIO18A1 IO Control Register */ ++#define SCU488 0x488 /* GPIO18A2 IO Control Register */ ++#define SCU48C 0x48c /* GPIO18A3 IO Control Register */ ++#define SCU490 0x490 /* GPIO18A4 IO Control Register */ ++#define SCU494 0x494 /* GPIO18A5 IO Control Register */ ++#define SCU498 0x498 /* GPIO18A6 IO Control Register */ ++#define SCU49C 0x49c /* GPIO18A7 IO Control Register */ ++#define SCU4A0 0x4A0 /* GPIO18B0 IO Control Register */ ++#define SCU4A4 0x4A4 /* GPIO18B1 IO Control Register */ ++#define SCU4A8 0x4A8 /* GPIO18B2 IO Control Register */ ++#define SCU4AC 0x4AC /* GPIO18B3 IO Control Register */ + -+out_free_misc: -+ misc_deregister(&bmc_device->miscdev); -+out_free_queue: -+ for (i = 0; i < ASPEED_QUEUE_NUM; i++) -+ sysfs_remove_bin_file(&pdev->dev.kobj, &bmc_device->queue[i].bin); -+out: -+ dev_warn(dev, "aspeed bmc device: driver init failed (ret=%d)!\n", ret); -+ return ret; -+} ++enum { ++ AC14, ++ AE15, ++ AD14, ++ AE14, ++ AF14, ++ AB13, ++ AB14, ++ AF15, ++ AF13, ++ AC13, ++ AD13, ++ AE13, ++ PORTA_U3, // SCU410[1:0] ++ PORTA_U2, // SCU410[3:2] ++ PORTB_U3, // SCU410[5:4] ++ PORTB_U2, // SCU410[7:6] ++ PORTA_U3_XHCI, // SCU410[9] ++ PORTA_U2_XHCI, // SCU410[9] ++ PORTB_U3_XHCI, // SCU410[10] ++ PORTB_U2_XHCI, // SCU410[10] ++ PORTA_MODE, // SCU410[25:24] ++ PORTB_MODE, // SCU410[29:28] ++ PORTA_U2_PHY, ++ PORTA_U3_PHY, ++ PORTB_U2_PHY, ++ PORTB_U3_PHY, ++ JTAG_PORT, ++ PCIERC0_PERST, ++ PCIERC1_PERST, ++}; + -+static void aspeed_bmc_device_remove(struct platform_device *pdev) -+{ -+ struct aspeed_bmc_device *bmc_device = platform_get_drvdata(pdev); -+ int i; ++GROUP_DECL(EMMCG1, AC14, AE15, AD14); ++GROUP_DECL(EMMCG4, AC14, AE15, AD14, AE14, AF14, AB13); ++GROUP_DECL(EMMCG8, AC14, AE15, AD14, AE14, AF14, AB13, AF13, AC13, AD13, AE13); ++GROUP_DECL(EMMCWPN, AF15); ++GROUP_DECL(EMMCCDN, AB14); ++GROUP_DECL(VGADDC, AD13, AE13); ++GROUP_DECL(VB1, AC14, AE15, AD14, AE14); ++GROUP_DECL(VB0, AF15, AB14, AF13, AC13); ++//USB3A ++//xhci: BMC/PCIE, vHub/PHY/EXT port ++GROUP_DECL(USB3AXHD, PORTA_U3, PORTA_U3_XHCI); ++GROUP_DECL(USB3AXHPD, PORTA_U3, PORTA_U3_XHCI); ++GROUP_DECL(USB3AXH, PORTA_U3, PORTA_U3_XHCI, PORTA_U3_PHY); ++GROUP_DECL(USB3AXHP, PORTA_U3, PORTA_U3_XHCI, PORTA_U3_PHY); ++GROUP_DECL(USB3AXH2B, PORTA_U3, PORTA_U3_XHCI, PORTB_U3_PHY); ++GROUP_DECL(USB3AXHP2B, PORTA_U3, PORTA_U3_XHCI, PORTB_U3_PHY); + -+ for (i = 0; i < ASPEED_QUEUE_NUM; i++) -+ sysfs_remove_bin_file(&pdev->dev.kobj, &bmc_device->queue[i].bin); -+ misc_deregister(&bmc_device->miscdev); -+ devm_free_irq(&pdev->dev, bmc_device->irq, bmc_device); -+ devm_free_irq(&pdev->dev, bmc_device->pcie_irq, bmc_device); ++//USB2A ++//xhci: BMC/PCIE, vHub/PHY/EXT port ++GROUP_DECL(USB2AXHD1, PORTA_U2, PORTA_U2_XHCI); ++GROUP_DECL(USB2AXHPD1, PORTA_U2, PORTA_U2_XHCI); ++GROUP_DECL(USB2AXH, PORTA_U2, PORTA_U2_XHCI, PORTA_U2_PHY); ++GROUP_DECL(USB2AXHP, PORTA_U2, PORTA_U2_XHCI, PORTA_U2_PHY); ++GROUP_DECL(USB2AXH2B, PORTA_U2, PORTA_U2_XHCI, PORTB_U2_PHY); ++GROUP_DECL(USB2AXHP2B, PORTA_U2, PORTA_U2_XHCI, PORTB_U2_PHY); ++// vhub to phy ++GROUP_DECL(USB2AD1, PORTA_U2, PORTA_U2_PHY); ++//ehci ++GROUP_DECL(USB2AHPD0, PORTA_MODE); ++GROUP_DECL(USB2AH, PORTA_MODE, PORTA_U2_PHY); ++GROUP_DECL(USB2AHP, PORTA_MODE, PORTA_U2_PHY); ++GROUP_DECL(USB2AD0, PORTA_MODE, PORTA_U2_PHY); + -+ iounmap(bmc_device->reg_base); ++//USB3B ++//xhci: BMC/PCIE, vHub/PHY/EXT port ++GROUP_DECL(USB3BXHD, PORTB_U3, PORTB_U3_XHCI); ++GROUP_DECL(USB3BXHPD, PORTB_U3, PORTB_U3_XHCI); ++GROUP_DECL(USB3BXH, PORTB_U3, PORTB_U3_XHCI, PORTB_U3_PHY); ++GROUP_DECL(USB3BXHP, PORTB_U3, PORTB_U3_XHCI, PORTB_U3_PHY); ++GROUP_DECL(USB3BXH2A, PORTB_U3, PORTB_U3_XHCI, PORTA_U3_PHY); ++GROUP_DECL(USB3BXHP2A, PORTB_U3, PORTB_U3_XHCI, PORTA_U3_PHY); + -+ devm_kfree(&pdev->dev, bmc_device); -+} ++//USB2B ++//xhci: BMC/PCIE, vHub/PHY/EXT port ++GROUP_DECL(USB2BXHD1, PORTB_U2, PORTB_U2_XHCI); ++GROUP_DECL(USB2BXHPD1, PORTB_U2, PORTB_U2_XHCI); ++GROUP_DECL(USB2BXH, PORTB_U2, PORTB_U2_XHCI, PORTB_U2_PHY); ++GROUP_DECL(USB2BXHP, PORTB_U2, PORTB_U2_XHCI, PORTB_U2_PHY); ++GROUP_DECL(USB2BXH2A, PORTB_U2, PORTB_U2_XHCI, PORTA_U2_PHY); ++GROUP_DECL(USB2BXHP2A, PORTB_U2, PORTB_U2_XHCI, PORTA_U2_PHY); ++// vhub to phy ++GROUP_DECL(USB2BD1, PORTB_U2, PORTB_U2_PHY); ++//ehci ++GROUP_DECL(USB2BHPD0, PORTB_MODE); ++GROUP_DECL(USB2BH, PORTB_MODE, PORTB_U2_PHY); ++GROUP_DECL(USB2BHP, PORTB_MODE, PORTB_U2_PHY); ++GROUP_DECL(USB2BD0, PORTB_MODE, PORTB_U2_PHY); ++//JTAG port ++GROUP_DECL(PSP, JTAG_PORT); ++GROUP_DECL(SSP, JTAG_PORT); ++GROUP_DECL(TSP, JTAG_PORT); ++GROUP_DECL(DDR, JTAG_PORT); ++GROUP_DECL(USB3A, JTAG_PORT); ++GROUP_DECL(USB3B, JTAG_PORT); ++GROUP_DECL(PCIEA, JTAG_PORT); ++GROUP_DECL(PCIEB, JTAG_PORT); ++GROUP_DECL(JTAGM0, JTAG_PORT); ++//PCIE RC PERST ++GROUP_DECL(PCIERC0PERST, PCIERC0_PERST); ++GROUP_DECL(PCIERC1PERST, PCIERC1_PERST); + -+static struct platform_driver aspeed_bmc_device_driver = { -+ .probe = aspeed_bmc_device_probe, -+ .remove = aspeed_bmc_device_remove, -+ .driver = { -+ .name = KBUILD_MODNAME, -+ .of_match_table = aspeed_bmc_device_of_matches, -+ }, ++static struct aspeed_pin_group aspeed_g7_soc0_pingroups[] = { ++ ASPEED_PINCTRL_GROUP(EMMCG1), ++ ASPEED_PINCTRL_GROUP(EMMCG4), ++ ASPEED_PINCTRL_GROUP(EMMCG8), ++ ASPEED_PINCTRL_GROUP(EMMCWPN), ++ ASPEED_PINCTRL_GROUP(EMMCCDN), ++ ASPEED_PINCTRL_GROUP(VGADDC), ++ ASPEED_PINCTRL_GROUP(VB1), ++ ASPEED_PINCTRL_GROUP(VB0), ++ ASPEED_PINCTRL_GROUP(USB3AXHD), ++ ASPEED_PINCTRL_GROUP(USB3AXHPD), ++ ASPEED_PINCTRL_GROUP(USB3AXH), ++ ASPEED_PINCTRL_GROUP(USB3AXHP), ++ ASPEED_PINCTRL_GROUP(USB3AXH2B), ++ ASPEED_PINCTRL_GROUP(USB3AXHP2B), ++ ASPEED_PINCTRL_GROUP(USB2AXHD1), ++ ASPEED_PINCTRL_GROUP(USB2AXHPD1), ++ ASPEED_PINCTRL_GROUP(USB2AXH), ++ ASPEED_PINCTRL_GROUP(USB2AXHP), ++ ASPEED_PINCTRL_GROUP(USB2AXH2B), ++ ASPEED_PINCTRL_GROUP(USB2AXHP2B), ++ ASPEED_PINCTRL_GROUP(USB2AD1), ++ ASPEED_PINCTRL_GROUP(USB2AHPD0), ++ ASPEED_PINCTRL_GROUP(USB2AH), ++ ASPEED_PINCTRL_GROUP(USB2AHP), ++ ASPEED_PINCTRL_GROUP(USB2AD0), ++ ASPEED_PINCTRL_GROUP(USB3BXHD), ++ ASPEED_PINCTRL_GROUP(USB3BXHPD), ++ ASPEED_PINCTRL_GROUP(USB3BXH), ++ ASPEED_PINCTRL_GROUP(USB3BXHP), ++ ASPEED_PINCTRL_GROUP(USB3BXH2A), ++ ASPEED_PINCTRL_GROUP(USB3BXHP2A), ++ ASPEED_PINCTRL_GROUP(USB2BXHD1), ++ ASPEED_PINCTRL_GROUP(USB2BXHPD1), ++ ASPEED_PINCTRL_GROUP(USB2BXH), ++ ASPEED_PINCTRL_GROUP(USB2BXHP), ++ ASPEED_PINCTRL_GROUP(USB2BXH2A), ++ ASPEED_PINCTRL_GROUP(USB2BXHP2A), ++ ASPEED_PINCTRL_GROUP(USB2BD1), ++ ASPEED_PINCTRL_GROUP(USB2BHPD0), ++ ASPEED_PINCTRL_GROUP(USB2BH), ++ ASPEED_PINCTRL_GROUP(USB2BHP), ++ ASPEED_PINCTRL_GROUP(USB2BD0), ++ ASPEED_PINCTRL_GROUP(PSP), ++ ASPEED_PINCTRL_GROUP(SSP), ++ ASPEED_PINCTRL_GROUP(TSP), ++ ASPEED_PINCTRL_GROUP(DDR), ++ ASPEED_PINCTRL_GROUP(USB3A), ++ ASPEED_PINCTRL_GROUP(USB3B), ++ ASPEED_PINCTRL_GROUP(PCIEA), ++ ASPEED_PINCTRL_GROUP(PCIEB), ++ ASPEED_PINCTRL_GROUP(JTAGM0), ++ ASPEED_PINCTRL_GROUP(PCIERC0PERST), ++ ASPEED_PINCTRL_GROUP(PCIERC1PERST), +}; + -+module_platform_driver(aspeed_bmc_device_driver); -+ -+MODULE_AUTHOR("Ryan Chen "); -+MODULE_DESCRIPTION("ASPEED BMC DEVICE Driver"); -+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 2026-04-08 18:03:48.310705320 +0000 -@@ -0,0 +1,255 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+// Copyright (C) ASPEED Technology Inc. -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DEVICE_NAME "aspeed-disp-intf" -+ -+#define AST2700_SCU_CHIP_ID 0x0 -+#define SCU_CPU_REVISION_ID_HW GENMASK(23, 16) -+ -+#define AST2700_SCU_PIN_SEL 0x414 -+#define AST2700_SCU_D1PLL_SEL GENMASK(13, 12) -+#define AST2700_SCU_DAC_SRC_SEL GENMASK(11, 10) -+#define AST2700_SCU_DP_SRC_SEL GENMASK(9, 8) -+ -+#define AST2600_SCU_PIN_SEL 0x0C0 -+#define AST2600_SCU_DP_SRC_SEL BIT(18) -+#define AST2600_SCU_DAC_SRC_SEL BIT(16) ++FUNC_DECL_(EMMC, "EMMCG1", "EMMCG4", "EMMCG8", "EMMCWPN", "EMMCCDN"); ++FUNC_DECL_(VGADDC, "VGADDC"); ++FUNC_DECL_(VB, "VB0", "VB1"); ++FUNC_DECL_(USB3A, "USB3AXHD", "USB3AXHPD", "USB3AXH", "USB3AXHP", "USB3AXH2B", ++ "USB3AXHP2B"); ++FUNC_DECL_(USB2A, "USB2AXHD1", "USB2AXHPD1", "USB2AXH", "USB2AXHP", "USB2AXH2B", ++ "USB2AXHP2B", "USB2AD1", "USB2AHPD0", "USB2AH", "USB2AHP", ++ "USB2AD0"); ++FUNC_DECL_(USB3B, "USB3BXHD", "USB3BXHPD", "USB3BXH", "USB3BXHP", "USB3BXH2A", ++ "USB3BXHP2A"); ++FUNC_DECL_(USB2B, "USB2BXHD1", "USB2BXHPD1", "USB2BXH", "USB2BXHP", "USB2BXH2A", ++ "USB2BXHP2A", "USB2BD1", "USB2BHPD0", "USB2BH", "USB2BHP", ++ "USB2BD0"); ++FUNC_DECL_(JTAG0, "PSP", "SSP", "TSP", "DDR", "USB3A", "USB3B", ++ "PCIEA", "PCIEB", "JTAGM0"); ++FUNC_DECL_(PCIERC, "PCIERC0PERST", "PCIERC1PERST"); + -+struct aspeed_disp_intf_config { -+ u8 version; -+ u32 dac_src_sel; -+ u32 dac_src_max; -+ u32 dac_src_min; -+ u32 dp_src_sel; -+ u32 dp_src_max; -+ u32 dp_src_min; ++static struct aspeed_pin_function aspeed_g7_soc0_funcs[] = { ++ ASPEED_PINCTRL_FUNC(EMMC), ++ ASPEED_PINCTRL_FUNC(VGADDC), ++ ASPEED_PINCTRL_FUNC(VB), ++ ASPEED_PINCTRL_FUNC(USB3A), ++ ASPEED_PINCTRL_FUNC(USB2A), ++ ASPEED_PINCTRL_FUNC(USB3B), ++ ASPEED_PINCTRL_FUNC(USB2B), ++ ASPEED_PINCTRL_FUNC(JTAG0), ++ ASPEED_PINCTRL_FUNC(PCIERC), +}; + -+struct aspeed_disp_intf { -+ struct device *dev; -+ struct miscdevice miscdev; -+ struct regmap *scu; -+ const struct aspeed_disp_intf_config *config; ++static const struct pinctrl_pin_desc aspeed_g7_soc0_pins[] = { ++ PINCTRL_PIN(AC14, "AC14"), ++ PINCTRL_PIN(AE15, "AE15"), ++ PINCTRL_PIN(AD14, "AD14"), ++ PINCTRL_PIN(AE14, "AE14"), ++ PINCTRL_PIN(AF14, "AF14"), ++ PINCTRL_PIN(AB13, "AB13"), ++ PINCTRL_PIN(AF15, "AF15"), ++ PINCTRL_PIN(AB14, "AB14"), ++ PINCTRL_PIN(AF13, "AF13"), ++ PINCTRL_PIN(AC13, "AC13"), ++ PINCTRL_PIN(AD13, "AD13"), ++ PINCTRL_PIN(AE13, "AE13"), ++ PINCTRL_PIN(PORTA_U3, "PORTA_U3"), ++ PINCTRL_PIN(PORTA_U2, "PORTA_U2"), ++ PINCTRL_PIN(PORTB_U3, "PORTB_U3"), ++ PINCTRL_PIN(PORTB_U2, "PORTB_U2"), ++ PINCTRL_PIN(PORTA_U3_XHCI, "PORTA_U3_XHCI"), ++ PINCTRL_PIN(PORTA_U2_XHCI, "PORTA_U2_XHCI"), ++ PINCTRL_PIN(PORTB_U3_XHCI, "PORTB_U3_XHCI"), ++ PINCTRL_PIN(PORTB_U2_XHCI, "PORTB_U2_XHCI"), ++ PINCTRL_PIN(PORTA_MODE, "PORTA_MODE"), ++ PINCTRL_PIN(PORTA_U3_PHY, "PORTA_U3_PHY"), ++ PINCTRL_PIN(PORTA_U2_PHY, "PORTA_U2_PHY"), ++ PINCTRL_PIN(PORTB_MODE, "PORTB_MODE"), ++ PINCTRL_PIN(PORTB_U3_PHY, "PORTB_U3_PHY"), ++ PINCTRL_PIN(PORTB_U2_PHY, "PORTB_U2_PHY"), ++ PINCTRL_PIN(JTAG_PORT, "JTAG_PORT"), ++ PINCTRL_PIN(PCIERC0_PERST, "PCIERC0_PERST"), ++ PINCTRL_PIN(PCIERC1_PERST, "PCIERC1_PERST"), +}; + -+static int dac_src, dp_src; ++FUNCFG_DESCL(AC14, PIN_CFG(EMMCG1, SCU400, BIT_MASK(0), BIT(0)), ++ PIN_CFG(EMMCG4, SCU400, BIT_MASK(0), BIT(0)), ++ PIN_CFG(EMMCG8, SCU400, BIT_MASK(0), BIT(0)), ++ PIN_CFG(VB1, SCU404, BIT_MASK(0), BIT(0))); ++FUNCFG_DESCL(AE15, PIN_CFG(EMMCG1, SCU400, BIT_MASK(1), BIT(1)), ++ PIN_CFG(EMMCG4, SCU400, BIT_MASK(1), BIT(1)), ++ PIN_CFG(EMMCG8, SCU400, BIT_MASK(1), BIT(1)), ++ PIN_CFG(VB1, SCU404, BIT_MASK(1), BIT(1))); ++FUNCFG_DESCL(AD14, PIN_CFG(EMMCG1, SCU400, BIT_MASK(2), BIT(2)), ++ PIN_CFG(EMMCG4, SCU400, BIT_MASK(2), BIT(2)), ++ PIN_CFG(EMMCG8, SCU400, BIT_MASK(2), BIT(2)), ++ PIN_CFG(VB1, SCU404, BIT_MASK(2), BIT(2))); ++FUNCFG_DESCL(AE14, PIN_CFG(EMMCG4, SCU400, BIT_MASK(3), BIT(3)), ++ PIN_CFG(EMMCG8, SCU400, BIT_MASK(3), BIT(3)), ++ PIN_CFG(VB1, SCU404, BIT_MASK(3), BIT(3))); ++FUNCFG_DESCL(AF14, PIN_CFG(EMMCG4, SCU400, BIT_MASK(4), BIT(4)), ++ PIN_CFG(EMMCG8, SCU400, BIT_MASK(4), BIT(4))); ++FUNCFG_DESCL(AB13, PIN_CFG(EMMCG4, SCU400, BIT_MASK(5), BIT(5)), ++ PIN_CFG(EMMCG8, SCU400, BIT_MASK(5), BIT(5))); ++FUNCFG_DESCL(AB14, PIN_CFG(EMMCCDN, SCU400, BIT_MASK(6), BIT(6)), ++ PIN_CFG(VB0, SCU404, BIT_MASK(6), BIT(6))); ++FUNCFG_DESCL(AF15, PIN_CFG(EMMCWPN, SCU400, BIT_MASK(7), BIT(7)), ++ PIN_CFG(VB0, SCU404, BIT_MASK(7), BIT(7))); ++FUNCFG_DESCL(AF13, PIN_CFG(EMMCG8, SCU400, BIT_MASK(8), BIT(8)), ++ PIN_CFG(VB0, SCU404, BIT_MASK(8), BIT(8))); ++FUNCFG_DESCL(AC13, PIN_CFG(EMMCG8, SCU400, BIT_MASK(9), BIT(9)), ++ PIN_CFG(VB0, SCU404, BIT_MASK(9), BIT(9))); ++FUNCFG_DESCL(AD13, PIN_CFG(EMMCG8, SCU400, BIT_MASK(10), BIT(10)), ++ PIN_CFG(VGADDC, SCU404, BIT_MASK(10), BIT(10))); ++FUNCFG_DESCL(AE13, PIN_CFG(EMMCG8, SCU400, BIT_MASK(11), BIT(11)), ++ PIN_CFG(VGADDC, SCU404, BIT_MASK(11), BIT(11))); ++FUNCFG_DESCL(PORTA_U3, PIN_CFG(USB3AXHD, SCU410, GENMASK(1, 0), 0), ++ PIN_CFG(USB3AXHPD, SCU410, GENMASK(1, 0), 0), ++ PIN_CFG(USB3AXH, SCU410, GENMASK(1, 0), 2), ++ PIN_CFG(USB3AXHP, SCU410, GENMASK(1, 0), 2), ++ PIN_CFG(USB3AXH2B, SCU410, GENMASK(1, 0), 3), ++ PIN_CFG(USB3AXHP2B, SCU410, GENMASK(1, 0), 3)); ++FUNCFG_DESCL(PORTA_U2, PIN_CFG(USB2AXHD1, SCU410, GENMASK(3, 2), 0), ++ PIN_CFG(USB2AXHPD1, SCU410, GENMASK(3, 2), 0), ++ PIN_CFG(USB2AXH, SCU410, GENMASK(3, 2), 2 << 2), ++ PIN_CFG(USB2AXHP, SCU410, GENMASK(3, 2), 2 << 2), ++ PIN_CFG(USB2AXH2B, SCU410, GENMASK(3, 2), 3 << 2), ++ PIN_CFG(USB2AXHP2B, SCU410, GENMASK(3, 2), 3 << 2), ++ PIN_CFG(USB2AD1, SCU410, GENMASK(3, 2), 1 << 2)); ++FUNCFG_DESCL(PORTB_U3, PIN_CFG(USB3BXHD, SCU410, GENMASK(5, 4), 0), ++ PIN_CFG(USB3BXHPD, SCU410, GENMASK(5, 4), 0), ++ PIN_CFG(USB3BXH, SCU410, GENMASK(5, 4), 2 << 4), ++ PIN_CFG(USB3BXHP, SCU410, GENMASK(5, 4), 2 << 4), ++ PIN_CFG(USB3BXH2A, SCU410, GENMASK(5, 4), 3 << 4), ++ PIN_CFG(USB3BXHP2A, SCU410, GENMASK(5, 4), 3 << 4)); ++FUNCFG_DESCL(PORTB_U2, PIN_CFG(USB2BXHD1, SCU410, GENMASK(7, 6), 0), ++ PIN_CFG(USB2BXHPD1, SCU410, GENMASK(7, 6), 0), ++ PIN_CFG(USB2BXH, SCU410, GENMASK(7, 6), 2 << 6), ++ PIN_CFG(USB2BXHP, SCU410, GENMASK(7, 6), 2 << 6), ++ PIN_CFG(USB2BXH2A, SCU410, GENMASK(7, 6), 3 << 6), ++ PIN_CFG(USB2BXHP2A, SCU410, GENMASK(7, 6), 3 << 6), ++ PIN_CFG(USB2BD1, SCU410, GENMASK(7, 6), 1 << 6)); ++FUNCFG_DESCL(PORTA_U3_XHCI, PIN_CFG(USB3AXHD, SCU410, BIT_MASK(9), 1 << 9), ++ PIN_CFG(USB3AXHPD, SCU410, BIT_MASK(9), 0), ++ PIN_CFG(USB3AXH, SCU410, BIT_MASK(9), 1 << 9), ++ PIN_CFG(USB3AXHP, SCU410, BIT_MASK(9), 0), ++ PIN_CFG(USB3AXH2B, SCU410, BIT_MASK(9), 1 << 9), ++ PIN_CFG(USB3AXHP2B, SCU410, BIT_MASK(9), 0)); ++FUNCFG_DESCL(PORTA_U2_XHCI, PIN_CFG(USB2AXHD1, SCU410, BIT_MASK(9), 1 << 9), ++ PIN_CFG(USB2AXHPD1, SCU410, BIT_MASK(9), 0), ++ PIN_CFG(USB2AXH, SCU410, BIT_MASK(9), 1 << 9), ++ PIN_CFG(USB2AXHP, SCU410, BIT_MASK(9), 0), ++ PIN_CFG(USB2AXH2B, SCU410, BIT_MASK(9), 1 << 9), ++ PIN_CFG(USB2AXHP2B, SCU410, BIT_MASK(9), 0)); ++FUNCFG_DESCL(PORTB_U3_XHCI, PIN_CFG(USB3BXHD, SCU410, BIT_MASK(10), 1 << 10), ++ PIN_CFG(USB3BXHPD, SCU410, BIT_MASK(10), 0), ++ PIN_CFG(USB3BXH, SCU410, BIT_MASK(10), 1 << 10), ++ PIN_CFG(USB3BXHP, SCU410, BIT_MASK(10), 0), ++ PIN_CFG(USB3BXH2A, SCU410, BIT_MASK(10), 1 << 10), ++ PIN_CFG(USB3BXHP2A, SCU410, BIT_MASK(10), 0)); ++FUNCFG_DESCL(PORTB_U2_XHCI, PIN_CFG(USB2BXHD1, SCU410, BIT_MASK(10), 1 << 10), ++ PIN_CFG(USB2BXHPD1, SCU410, BIT_MASK(10), 0), ++ PIN_CFG(USB2BXH, SCU410, BIT_MASK(10), 1 << 10), ++ PIN_CFG(USB2BXHP, SCU410, BIT_MASK(10), 0), ++ PIN_CFG(USB2BXH2A, SCU410, BIT_MASK(10), 1 << 10), ++ PIN_CFG(USB2BXHP2A, SCU410, BIT_MASK(10), 0)); ++FUNCFG_DESCL(PORTA_MODE, PIN_CFG(USB2AHPD0, SCU410, GENMASK(25, 24), 0), ++ PIN_CFG(USB2AH, SCU410, GENMASK(25, 24), 2 << 24), ++ PIN_CFG(USB2AHP, SCU410, GENMASK(25, 24), 3 << 24), ++ PIN_CFG(USB2AD0, SCU410, GENMASK(25, 24), 1 << 24)); ++FUNCFG_DESCL(PORTB_MODE, PIN_CFG(USB2BHPD0, SCU410, GENMASK(29, 28), 0), ++ PIN_CFG(USB2BH, SCU410, GENMASK(29, 28), 2 << 28), ++ PIN_CFG(USB2BHP, SCU410, GENMASK(29, 28), 3 << 28), ++ PIN_CFG(USB2BD0, SCU410, GENMASK(29, 28), 1 << 28)); ++FUNCFG_DESCL(PORTA_U3_PHY); ++FUNCFG_DESCL(PORTA_U2_PHY); ++FUNCFG_DESCL(PORTB_U3_PHY); ++FUNCFG_DESCL(PORTB_U2_PHY); ++FUNCFG_DESCL(JTAG_PORT, PIN_CFG(PSP, SCU408, GENMASK(12, 5), 0x0 << 5), ++ PIN_CFG(SSP, SCU408, GENMASK(12, 5), 0x41 << 5), ++ PIN_CFG(TSP, SCU408, GENMASK(12, 5), 0x42 << 5), ++ PIN_CFG(DDR, SCU408, GENMASK(12, 5), 0x43 << 5), ++ PIN_CFG(USB3A, SCU408, GENMASK(12, 5), 0x44 << 5), ++ PIN_CFG(USB3B, SCU408, GENMASK(12, 5), 0x45 << 5), ++ PIN_CFG(PCIEA, SCU408, GENMASK(12, 5), 0x46 << 5), ++ PIN_CFG(PCIEB, SCU408, GENMASK(12, 5), 0x47 << 5), ++ PIN_CFG(JTAGM0, SCU408, GENMASK(12, 5), 0x8 << 5)); ++FUNCFG_DESCL(PCIERC0_PERST, PIN_CFG(PCIERC0PERST, SCU200, BIT_MASK(21), 1 << 21)); ++FUNCFG_DESCL(PCIERC1_PERST, PIN_CFG(PCIERC1PERST, SCU200, BIT_MASK(19), 1 << 19)); + -+static const struct aspeed_disp_intf_config ast2600_config = { -+ .version = 6, -+ .dac_src_sel = AST2600_SCU_PIN_SEL, -+ .dac_src_max = 1, -+ .dac_src_min = 0, -+ .dp_src_sel = AST2600_SCU_PIN_SEL, -+ .dp_src_max = 1, -+ .dp_src_min = 0, ++static const struct aspeed_g7_pincfg pin_cfg[] = { ++ PINCFG_PIN(AC14), PINCFG_PIN(AE15), ++ PINCFG_PIN(AD14), PINCFG_PIN(AE14), ++ PINCFG_PIN(AF14), PINCFG_PIN(AB13), ++ PINCFG_PIN(AB14), PINCFG_PIN(AF15), ++ PINCFG_PIN(AF13), PINCFG_PIN(AC13), ++ PINCFG_PIN(AD13), PINCFG_PIN(AE13), ++ PINCFG_PIN(PORTA_U3), PINCFG_PIN(PORTA_U2), ++ PINCFG_PIN(PORTB_U3), PINCFG_PIN(PORTB_U2), ++ PINCFG_PIN(PORTA_U3_XHCI), PINCFG_PIN(PORTA_U2_XHCI), ++ PINCFG_PIN(PORTB_U3_XHCI), PINCFG_PIN(PORTB_U2_XHCI), ++ PINCFG_PIN(PORTA_MODE), PINCFG_PIN(PORTB_MODE), ++ PINCFG_PIN(PORTA_U3_PHY), PINCFG_PIN(PORTA_U2_PHY), ++ PINCFG_PIN(PORTB_U3_PHY), PINCFG_PIN(PORTB_U2_PHY), ++ PINCFG_PIN(JTAG_PORT), PINCFG_PIN(PCIERC0_PERST), ++ PINCFG_PIN(PCIERC1_PERST), +}; + -+static const struct aspeed_disp_intf_config ast2700_config = { -+ .version = 7, -+ .dac_src_sel = AST2700_SCU_PIN_SEL, -+ .dac_src_max = 2, -+ .dac_src_min = 0, -+ .dp_src_sel = AST2700_SCU_PIN_SEL, -+ .dp_src_max = 2, -+ .dp_src_min = 0, ++static const struct pinctrl_ops aspeed_g7_soc0_pinctrl_ops = { ++ .get_groups_count = aspeed_pinctrl_get_groups_count, ++ .get_group_name = aspeed_pinctrl_get_group_name, ++ .get_group_pins = aspeed_pinctrl_get_group_pins, ++ .pin_dbg_show = aspeed_pinctrl_pin_dbg_show, ++ .dt_node_to_map = pinconf_generic_dt_node_to_map_all, ++ .dt_free_map = pinctrl_utils_free_map, +}; + -+static ssize_t dac_src_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct aspeed_disp_intf *intf = dev_get_drvdata(dev); -+ const struct aspeed_disp_intf_config *config = intf->config; -+ u32 val; -+ -+ regmap_read(intf->scu, config->dac_src_sel, &val); -+ dac_src = (config->version == 6) -+ ? FIELD_GET(AST2600_SCU_DAC_SRC_SEL, val) -+ : FIELD_GET(AST2700_SCU_DAC_SRC_SEL, val); -+ return sysfs_emit(buf, "%d\n", dac_src); -+} -+ -+static ssize_t dac_src_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct aspeed_disp_intf *intf = dev_get_drvdata(dev); -+ const struct aspeed_disp_intf_config *config = intf->config; -+ int src, res; -+ -+ res = kstrtoint(buf, 0, &src); -+ if (res) -+ return res; -+ -+ if (src < config->dac_src_min || src > config->dac_src_max) { -+ dev_err(intf->dev, "Invalid dac_src(max:%d, min:%d)\n", -+ config->dac_src_max, config->dac_src_min); -+ return -1; -+ } ++static const struct pinmux_ops aspeed_g7_soc0_pinmux_ops = { ++ .get_functions_count = aspeed_pinmux_get_fn_count, ++ .get_function_name = aspeed_pinmux_get_fn_name, ++ .get_function_groups = aspeed_pinmux_get_fn_groups, ++ .set_mux = aspeed_g7_pinmux_set_mux, ++ .gpio_request_enable = aspeed_g7_gpio_request_enable, ++ .strict = true, ++}; + -+ dac_src = src; -+ if (config->version == 6) { -+ regmap_update_bits(intf->scu, config->dac_src_sel, AST2600_SCU_DAC_SRC_SEL, -+ FIELD_PREP(AST2600_SCU_DAC_SRC_SEL, src)); -+ } else { -+ u32 id; -+ u32 mask = AST2700_SCU_DAC_SRC_SEL; -+ u32 val = FIELD_PREP(AST2700_SCU_DAC_SRC_SEL, src); ++static const struct pinconf_ops aspeed_g7_soc0_pinconf_ops = { ++ .is_generic = true, ++ .pin_config_get = aspeed_pin_config_get, ++ .pin_config_set = aspeed_pin_config_set, ++ .pin_config_group_get = aspeed_pin_config_group_get, ++ .pin_config_group_set = aspeed_pin_config_group_set, ++}; + -+ // D1PLL used in A0 only -+ regmap_read(intf->scu, AST2700_SCU_CHIP_ID, &id); -+ if (FIELD_GET(SCU_CPU_REVISION_ID_HW, id) != 0) { -+ mask |= AST2700_SCU_D1PLL_SEL; -+ val |= FIELD_PREP(AST2700_SCU_D1PLL_SEL, src); -+ } ++/* pinctrl_desc */ ++static struct pinctrl_desc aspeed_g7_soc0_pinctrl_desc = { ++ .name = "aspeed-g7-soc0-pinctrl", ++ .pins = aspeed_g7_soc0_pins, ++ .npins = ARRAY_SIZE(aspeed_g7_soc0_pins), ++ .pctlops = &aspeed_g7_soc0_pinctrl_ops, ++ .pmxops = &aspeed_g7_soc0_pinmux_ops, ++ .confops = &aspeed_g7_soc0_pinconf_ops, ++ .owner = THIS_MODULE, ++}; + -+ regmap_update_bits(intf->scu, config->dac_src_sel, mask, val); -+ } -+ return count; -+} ++static struct aspeed_pin_config aspeed_g7_configs[] = { ++ /* GPIO18A */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { AC14, AC14 }, SCU480, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AE15, AE15 }, SCU484, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AD14, AD14 }, SCU488, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AE14, AE14 }, SCU48C, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AF14, AF14 }, SCU490, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AB13, AB13 }, SCU494, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AB14, AB14 }, SCU498, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AF15, AF15 }, SCU49C, GENMASK(3, 0) }, ++ /* GPIO18B */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { AF13, AF13 }, SCU4A0, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AC13, AC13 }, SCU4A4, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AD13, AD13 }, SCU4A8, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AE13, AE13 }, SCU4AC, GENMASK(3, 0) }, ++}; + -+static DEVICE_ATTR_RW(dac_src); ++static const struct aspeed_pin_config_map aspeed_g7_pin_config_map[] = { ++ { PIN_CONFIG_DRIVE_STRENGTH, 0, 0, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, 1, 1, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, 2, 2, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, 3, 3, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, 4, 4, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, 5, 5, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, 6, 6, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, 7, 7, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, 8, 8, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, 9, 9, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, 10, 10, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, 11, 11, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, 12, 12, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, 13, 13, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, 14, 14, GENMASK(3, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, 15, 15, GENMASK(3, 0) }, + -+static ssize_t dp_src_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct aspeed_disp_intf *intf = dev_get_drvdata(dev); -+ const struct aspeed_disp_intf_config *config = intf->config; -+ u32 val; ++}; + -+ regmap_read(intf->scu, config->dp_src_sel, &val); -+ dp_src = (config->version == 6) -+ ? FIELD_GET(AST2600_SCU_DP_SRC_SEL, val) -+ : FIELD_GET(AST2700_SCU_DP_SRC_SEL, val); -+ return sysfs_emit(buf, "%d\n", dp_src); -+} ++static struct aspeed_pinctrl_data aspeed_g7_pinctrl_data = { ++ .pins = aspeed_g7_soc0_pins, ++ .npins = ARRAY_SIZE(aspeed_g7_soc0_pins), ++ .pinmux = { ++ .groups = aspeed_g7_soc0_pingroups, ++ .ngroups = ARRAY_SIZE(aspeed_g7_soc0_pingroups), ++ .functions = aspeed_g7_soc0_funcs, ++ .nfunctions = ARRAY_SIZE(aspeed_g7_soc0_funcs), ++ .configs_g7 = pin_cfg, ++ .nconfigs_g7 = ARRAY_SIZE(pin_cfg), ++ }, ++ .configs = aspeed_g7_configs, ++ .nconfigs = ARRAY_SIZE(aspeed_g7_configs), ++ .confmaps = aspeed_g7_pin_config_map, ++ .nconfmaps = ARRAY_SIZE(aspeed_g7_pin_config_map), ++}; + -+static ssize_t dp_src_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t count) ++static int aspeed_g7_soc0_pinctrl_probe(struct platform_device *pdev) +{ -+ struct aspeed_disp_intf *intf = dev_get_drvdata(dev); -+ const struct aspeed_disp_intf_config *config = intf->config; -+ int src, res; -+ -+ res = kstrtoint(buf, 0, &src); -+ if (res) -+ return res; -+ -+ if (src < config->dp_src_min || src > config->dp_src_max) { -+ dev_err(intf->dev, "Invalid dp_src(max:%d, min:%d)\n", -+ config->dp_src_max, config->dp_src_min); -+ return -1; -+ } -+ -+ dp_src = src; -+ if (config->version == 6) { -+ regmap_update_bits(intf->scu, config->dp_src_sel, AST2600_SCU_DP_SRC_SEL, -+ FIELD_PREP(AST2600_SCU_DP_SRC_SEL, src)); -+ } else { -+ u32 val; -+ -+ regmap_update_bits(intf->scu, config->dp_src_sel, AST2700_SCU_DP_SRC_SEL, -+ FIELD_PREP(AST2700_SCU_DP_SRC_SEL, src)); -+ -+ // D1PLL used in A0 only -+ regmap_read(intf->scu, AST2700_SCU_CHIP_ID, &val); -+ if (FIELD_GET(SCU_CPU_REVISION_ID_HW, val) == 0) { -+ regmap_update_bits(intf->scu, config->dp_src_sel, AST2700_SCU_D1PLL_SEL, -+ FIELD_PREP(AST2700_SCU_D1PLL_SEL, src)); -+ } -+ } -+ -+ return count; ++ return aspeed_pinctrl_probe(pdev, &aspeed_g7_soc0_pinctrl_desc, ++ &aspeed_g7_pinctrl_data); +} + -+static DEVICE_ATTR_RW(dp_src); -+ -+static struct attribute *aspeed_disp_intf_attrs[] = { -+ &dev_attr_dac_src.attr, -+ &dev_attr_dp_src.attr, -+ NULL, ++static const struct of_device_id aspeed_g7_soc0_pinctrl_match[] = { ++ { .compatible = "aspeed,ast2700-soc0-pinctrl" }, ++ {} +}; ++MODULE_DEVICE_TABLE(of, aspeed_g7_soc0_pinctrl_match); + -+static const struct attribute_group aspeed_disp_intf_attgrp = { -+ .name = NULL, -+ .attrs = aspeed_disp_intf_attrs, ++static struct platform_driver aspeed_g7_soc0_pinctrl_driver = { ++ .probe = aspeed_g7_soc0_pinctrl_probe, ++ .driver = { ++ .name = "aspeed-g7-soc0-pinctrl", ++ .of_match_table = aspeed_g7_soc0_pinctrl_match, ++ .suppress_bind_attrs = true, ++ }, +}; + -+static int aspeed_disp_intf_probe(struct platform_device *pdev) ++static int __init aspeed_g7_soc0_pinctrl_register(void) +{ -+ struct aspeed_disp_intf *intf; -+ struct device *dev = &pdev->dev; -+ int ret; -+ -+ intf = devm_kzalloc(&pdev->dev, sizeof(struct aspeed_disp_intf), GFP_KERNEL); -+ if (!intf) -+ return -ENOMEM; -+ -+ dev_set_drvdata(&pdev->dev, intf); ++ return platform_driver_register(&aspeed_g7_soc0_pinctrl_driver); ++} ++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 @@ ++// SPDX-License-Identifier: GPL-2.0 + -+ intf->config = of_device_get_match_data(&pdev->dev); -+ if (!intf->config) -+ return -ENODEV; ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "pinctrl-aspeed.h" + -+ intf->dev = dev; -+ intf->scu = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); -+ if (IS_ERR(intf->scu)) { -+ dev_err(dev, "failed to find SCU regmap\n"); -+ return PTR_ERR(intf->scu); -+ } ++#define SCU3B0 0x3B0 /* USB Controller Register */ ++#define SCU3B4 0x3B4 /* USB Controller Lock Register */ ++#define SCU3B8 0x3B8 /* USB Controller Secure Register #1 */ ++#define SCU3BC 0x3BC /* USB Controller Secure Register #2 */ ++#define SCU3C0 0x3C0 /* USB Controller Secure Register #3 */ ++#define SCU400 0x400 /* Multi-function Pin Control #1 */ ++#define SCU404 0x404 /* Multi-function Pin Control #2 */ ++#define SCU408 0x408 /* Multi-function Pin Control #3 */ ++#define SCU40C 0x40C /* Multi-function Pin Control #4 */ ++#define SCU410 0x410 /* Multi-function Pin Control #5 */ ++#define SCU414 0x414 /* Multi-function Pin Control #6 */ ++#define SCU418 0x418 /* Multi-function Pin Control #7 */ ++#define SCU41C 0x41C /* Multi-function Pin Control #8 */ ++#define SCU420 0x420 /* Multi-function Pin Control #9 */ ++#define SCU424 0x424 /* Multi-function Pin Control #10 */ ++#define SCU428 0x428 /* Multi-function Pin Control #11 */ ++#define SCU42C 0x42C /* Multi-function Pin Control #12 */ ++#define SCU430 0x430 /* Multi-function Pin Control #13 */ ++#define SCU434 0x434 /* Multi-function Pin Control #14 */ ++#define SCU438 0x438 /* Multi-function Pin Control #15 */ ++#define SCU43C 0x43C /* Multi-function Pin Control #16 */ ++#define SCU440 0x440 /* Multi-function Pin Control #17 */ ++#define SCU444 0x444 /* Multi-function Pin Control #18 */ ++#define SCU448 0x448 /* Multi-function Pin Control #19 */ ++#define SCU44C 0x44C /* Multi-function Pin Control #20 */ ++#define SCU450 0x450 /* Multi-function Pin Control #21 */ ++#define SCU454 0x454 /* Multi-function Pin Control #22 */ ++#define SCU458 0x458 /* Multi-function Pin Control #23 */ ++#define SCU45C 0x45C /* Multi-function Pin Control #24 */ ++#define SCU460 0x460 /* Multi-function Pin Control #25 */ ++#define SCU464 0x464 /* Multi-function Pin Control #26 */ ++#define SCU468 0x468 /* Multi-function Pin Control #27 */ ++#define SCU46C 0x46C /* Multi-function Pin Control #28 */ ++#define SCU470 0x470 /* Multi-function Pin Control #29 */ ++#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 */ ++#define SCU4C8 0x4C8 /* Driving Strength #2 L-M */ ++#define SCU4CC 0x4CC /* Driving Strength #3 N-O */ ++#define SCU4D0 0x4D0 /* Driving Strength #4 P-Q */ ++#define SCU4D4 0x4D4 /* Driving Strength #5 R-S */ ++#define SCU4D8 0x4D8 /* Driving Strength #6 T-U */ ++#define SCU4DC 0x4DC /* Driving Strength #7 W */ + -+ intf->miscdev.minor = MISC_DYNAMIC_MINOR; -+ intf->miscdev.name = DEVICE_NAME; -+ intf->miscdev.parent = dev; -+ ret = misc_register(&intf->miscdev); -+ if (ret) { -+ dev_err(dev, "Unable to register device\n"); -+ return ret; -+ } ++#define SCU908 0x908 /* PCIe RC PERST Pin Control */ + -+ ret = sysfs_create_group(&dev->kobj, &aspeed_disp_intf_attgrp); -+ if (ret != 0) -+ dev_warn(dev, "failed to register attributes\n"); ++enum { ++ C16, ++ C14, ++ C11, ++ D9, ++ F14, ++ D10, ++ C12, ++ C13, ++ AC26, ++ AA25, ++ AB23, ++ U22, ++ V21, ++ N26, ++ P25, ++ N25, ++ V23, ++ W22, ++ AB26, ++ AD26, ++ P26, ++ AE26, ++ AF26, ++ AF25, ++ AE25, ++ AD25, ++ AF23, ++ AF20, ++ AF21, ++ AE21, ++ AE23, ++ AD22, ++ AF17, ++ AA16, ++ Y16, ++ V17, ++ J13, ++ AB16, ++ AC16, ++ AF16, ++ AA15, ++ AB15, ++ AC15, ++ AD15, ++ Y15, ++ AA14, ++ W16, ++ V16, ++ AB18, ++ AC18, ++ K13, ++ AA17, ++ AB17, ++ AD16, ++ AC17, ++ AD17, ++ AE16, ++ AE17, ++ AB24, ++ W26, ++ HOLE0, ++ HOLE1, ++ HOLE2, ++ HOLE3, ++ W25, ++ Y23, ++ Y24, ++ W21, ++ AA23, ++ AC22, ++ AB22, ++ Y21, ++ AE20, ++ AF19, ++ Y22, ++ AA20, ++ AA22, ++ AB20, ++ AF18, ++ AE19, ++ AD20, ++ AC20, ++ AA21, ++ AB21, ++ AC19, ++ AE18, ++ AD19, ++ AD18, ++ U25, ++ U26, ++ Y26, ++ AA24, ++ R25, ++ AA26, ++ R26, ++ Y25, ++ B16, ++ D14, ++ B15, ++ B14, ++ C17, ++ B13, ++ E14, ++ C15, ++ D24, ++ B23, ++ B22, ++ C23, ++ B18, ++ B21, ++ M15, ++ B19, ++ B26, ++ A25, ++ A24, ++ B24, ++ E26, ++ A21, ++ A19, ++ A18, ++ D26, ++ C26, ++ A23, ++ A22, ++ B25, ++ F26, ++ A26, ++ A14, ++ E10, ++ E13, ++ D12, ++ F10, ++ E11, ++ F11, ++ F13, ++ N15, ++ C20, ++ C19, ++ A8, ++ R14, ++ A7, ++ P14, ++ D20, ++ A6, ++ B6, ++ N14, ++ B7, ++ B8, ++ B9, ++ M14, ++ J11, ++ E7, ++ D19, ++ B11, ++ D15, ++ B12, ++ B10, ++ P13, ++ C18, ++ C6, ++ C7, ++ D7, ++ N13, ++ C8, ++ C9, ++ C10, ++ M16, ++ A15, ++ G11, ++ H7, ++ H8, ++ H9, ++ H10, ++ H11, ++ J9, ++ J10, ++ E9, ++ F9, ++ F8, ++ M13, ++ F7, ++ D8, ++ E8, ++ L12, ++ F12, ++ E12, ++ J12, ++ G7, ++ G8, ++ G9, ++ G10, ++ K12, ++ W17, ++ V18, ++ W18, ++ Y17, ++ AA18, ++ AA13, ++ Y18, ++ AA12, ++ W20, ++ V20, ++ Y11, ++ V14, ++ V19, ++ W14, ++ Y20, ++ AB19, ++ U21, ++ T24, ++ V24, ++ V22, ++ T23, ++ AC25, ++ AB25, ++ AC24, ++ SGMII0, ++ PCIERC2_PERST, ++ PORTC_MODE, // SCU3B0[1:0] ++ PORTD_MODE, // SCU3B0[3:2] ++}; + -+ return 0; -+} ++GROUP_DECL(ESPI0, B16, D14, B15, B14, C17, B13, E14, C15); ++GROUP_DECL(ESPI1, C16, C14, C11, D9, F14, D10, C12, C13); ++GROUP_DECL(LPC0, AF26, AF25, B16, D14, B15, B14, C17, B13, E14, C15); ++GROUP_DECL(LPC1, C16, C14, C11, D9, F14, D10, C12, C13, AE16, AE17); ++GROUP_DECL(SD, C16, C14, C11, D9, F14, D10, C12, C13); ++GROUP_DECL(VPI, C16, C14, C11, D9, F14, D10, C12, C13, AC26, AA25, AB23, U22, ++ V21, N26, P25, N25, V23, W22, AB26, AD26, P26, AE26, AF26, AF25, ++ AE25, AD25, AF23, AF20, AF21, AE21); ++GROUP_DECL(OSCCLK, C17); ++GROUP_DECL(TACH0, AC26); ++GROUP_DECL(TACH1, AA25); ++GROUP_DECL(TACH2, AB23); ++GROUP_DECL(TACH3, U22); ++GROUP_DECL(THRU0, AC26, AA25); ++GROUP_DECL(THRU1, AB23, U22); ++GROUP_DECL(TACH4, V21); ++GROUP_DECL(TACH5, N26); ++GROUP_DECL(TACH6, P25); ++GROUP_DECL(TACH7, N25); ++GROUP_DECL(NTCS5, V21); ++GROUP_DECL(NDCD5, N26); ++GROUP_DECL(NDSR5, P25); ++GROUP_DECL(NRI5, N25); ++GROUP_DECL(SALT12, AB26); ++GROUP_DECL(SALT13, AD26); ++GROUP_DECL(SALT14, P26); ++GROUP_DECL(SALT15, AE26); ++GROUP_DECL(NDTR5, V23); ++GROUP_DECL(NRTS5, W22); ++GROUP_DECL(NCTS6, AB26); ++GROUP_DECL(NDCD6, AD26); ++GROUP_DECL(NDSR6, P26); ++GROUP_DECL(NRI6, AE26); ++GROUP_DECL(NDTR6, AF26); ++GROUP_DECL(NRTS6, AF25); ++GROUP_DECL(TACH8, V23); ++GROUP_DECL(TACH9, W22); ++GROUP_DECL(TACH10, AB26); ++GROUP_DECL(TACH11, AD26); ++GROUP_DECL(TACH12, P26); ++GROUP_DECL(TACH13, AE26); ++GROUP_DECL(TACH14, AF26); ++GROUP_DECL(TACH15, AF25); ++GROUP_DECL(SPIM0, AE25, AD25, AF23, AF20, AF21, AE21, AE23); ++GROUP_DECL(PWM0, AE25); ++GROUP_DECL(PWM1, AD25); ++GROUP_DECL(PWM2, AF23); ++GROUP_DECL(PWM3, AF20); ++GROUP_DECL(PWM4, AF21); ++GROUP_DECL(PWM5, AE21); ++GROUP_DECL(PWM6, AE23); ++GROUP_DECL(PWM7, AD22); ++GROUP_DECL(SIOPBON0, AE25); ++GROUP_DECL(SIOPBIN0, AD25); ++GROUP_DECL(SIOSCIN0, AF23); ++GROUP_DECL(SIOS3N0, AF20); ++GROUP_DECL(SIOS5N0, AF21); ++GROUP_DECL(SIOPWREQN0, AE21); ++GROUP_DECL(SIOONCTRLN0, AE23); ++GROUP_DECL(SIOPWRGD0, AD22); ++GROUP_DECL(NCTS0, AF17); ++GROUP_DECL(NDCD0, AA16); ++GROUP_DECL(NDSR0, Y16); ++GROUP_DECL(NRI0, V17); ++GROUP_DECL(NDTR0, J13); ++GROUP_DECL(NRTS0, AB16); ++GROUP_DECL(TXD0, AC16); ++GROUP_DECL(RXD0, AF16); ++GROUP_DECL(NCTS1, AA15); ++GROUP_DECL(NDCD1, AB15); ++GROUP_DECL(NDSR1, AC15); ++GROUP_DECL(NRI1, AD15); ++GROUP_DECL(NDTR1, Y15); ++GROUP_DECL(NRTS1, AA14); ++GROUP_DECL(TXD1, W16); ++GROUP_DECL(RXD1, V16); ++GROUP_DECL(TXD2, AB18); ++GROUP_DECL(RXD2, AC18); ++GROUP_DECL(TXD3, K13); ++GROUP_DECL(RXD3, AA17); ++GROUP_DECL(NCTS5, V21); ++GROUP_DECL(TXD5, AB17); ++GROUP_DECL(RXD5, AD16); ++GROUP_DECL(TXD6, AC17); ++GROUP_DECL(RXD6, AD17); ++GROUP_DECL(TXD7, AE16); ++GROUP_DECL(RXD7, AE17); ++GROUP_DECL(TXD8, M15); ++GROUP_DECL(RXD8, B19); ++GROUP_DECL(TXD9, B26); ++GROUP_DECL(RXD9, A25); ++GROUP_DECL(TXD10, A24); ++GROUP_DECL(RXD10, B24); ++GROUP_DECL(TXD11, E26); ++GROUP_DECL(RXD11, A21); ++GROUP_DECL(SPIM1, K13, AA17, AB17, AD16, AC17, AD17, AE16, AE17); ++GROUP_DECL(WDTRST0N, K13); ++GROUP_DECL(WDTRST1N, AA17); ++GROUP_DECL(WDTRST2N, AB17); ++GROUP_DECL(WDTRST3N, AD16); ++GROUP_DECL(WDTRST4N, AC25); ++GROUP_DECL(WDTRST5N, AB25); ++GROUP_DECL(WDTRST6N, AC24); ++GROUP_DECL(WDTRST7N, AB24); ++GROUP_DECL(PWM8, K13); ++GROUP_DECL(PWM9, AA17); ++GROUP_DECL(PWM10, AB17); ++GROUP_DECL(PWM11, AD16); ++GROUP_DECL(PWM12, AC17); ++GROUP_DECL(PWM13, AD17); ++GROUP_DECL(PWM14, AE16); ++GROUP_DECL(PWM15, AE17); ++GROUP_DECL(SALT0, AC17); ++GROUP_DECL(SALT1, AD17); ++GROUP_DECL(SALT2, AC15); ++GROUP_DECL(SALT3, AD15); ++GROUP_DECL(FSI0, AD20, AC20); ++GROUP_DECL(FSI1, AA21, AB21); ++GROUP_DECL(FSI2, AC19, AE18); ++GROUP_DECL(FSI3, AD19, AD18); ++GROUP_DECL(SPIM2, W25, Y23, Y24, W21, AA23, AC22, AB22, Y21); ++GROUP_DECL(SALT4, W17); ++GROUP_DECL(SALT5, V18); ++GROUP_DECL(SALT6, W18); ++GROUP_DECL(SALT7, Y17); ++GROUP_DECL(SALT8, AA18); ++GROUP_DECL(SALT9, AA13); ++GROUP_DECL(SALT10, Y18); ++GROUP_DECL(SALT11, AA12); ++GROUP_DECL(ADC0, W17); ++GROUP_DECL(ADC1, V18); ++GROUP_DECL(ADC2, W18); ++GROUP_DECL(ADC3, Y17); ++GROUP_DECL(ADC4, AA18); ++GROUP_DECL(ADC5, AA13); ++GROUP_DECL(ADC6, Y18); ++GROUP_DECL(ADC7, AA12); ++GROUP_DECL(ADC8, W20); ++GROUP_DECL(ADC9, V20); ++GROUP_DECL(ADC10, Y11); ++GROUP_DECL(ADC11, V14); ++GROUP_DECL(ADC12, V19); ++GROUP_DECL(ADC13, W14); ++GROUP_DECL(ADC14, Y20); ++GROUP_DECL(ADC15, AB19); ++GROUP_DECL(AUXPWRGOOD0, W14); ++GROUP_DECL(AUXPWRGOOD1, Y20); ++GROUP_DECL(SGPM0, U21, T24, V22, T23); ++GROUP_DECL(SGPM1, AC25, AB25, AB24, W26); ++GROUP_DECL(I2C0, G11, H7); ++GROUP_DECL(I2C1, H8, H9); ++GROUP_DECL(I2C2, H10, H11); ++GROUP_DECL(I2C3, J9, J10); ++GROUP_DECL(I2C4, E9, F9); ++GROUP_DECL(I2C5, F8, M13); ++GROUP_DECL(I2C6, F7, D8); ++GROUP_DECL(I2C7, E8, L12); ++GROUP_DECL(I2C8, F12, E12); ++GROUP_DECL(I2C9, J12, G7); ++GROUP_DECL(I2C10, G8, G9); ++GROUP_DECL(I2C11, G10, K12); ++GROUP_DECL(I2C12, AC18, AA17); ++GROUP_DECL(I2C13, AB17, AD16); ++GROUP_DECL(I2C14, AC17, AD17); ++GROUP_DECL(I2C15, AE16, AE17); ++GROUP_DECL(DI2C0, C16, D9); ++GROUP_DECL(DI2C1, C14, F14); ++GROUP_DECL(DI2C2, D10, C12); ++GROUP_DECL(DI2C3, C11, C13); ++GROUP_DECL(DI2C8, U25, U26); ++GROUP_DECL(DI2C9, Y26, AA24); ++GROUP_DECL(DI2C10, R25, AA26); ++GROUP_DECL(DI2C11, R26, Y25); ++GROUP_DECL(DI2C12, W25, Y23); ++GROUP_DECL(DI2C13, Y24, W21); ++GROUP_DECL(DI2C14, AA23, AC22); ++GROUP_DECL(DI2C15, AB22, Y21); ++GROUP_DECL(LTPI_PS_I2C0, G11, H7); ++GROUP_DECL(LTPI_PS_I2C1, H8, H9); ++GROUP_DECL(LTPI_PS_I2C2, H10, H11); ++GROUP_DECL(LTPI_PS_I2C3, J9, J10); ++GROUP_DECL(SIOPBON1, AF17); ++GROUP_DECL(SIOPBIN1, AA16); ++GROUP_DECL(SIOSCIN1, Y16); ++GROUP_DECL(SIOS3N1, V17); ++GROUP_DECL(SIOS5N1, J13); ++GROUP_DECL(SIOPWREQN1, AB16); ++GROUP_DECL(SIOONCTRLN1, AA15); ++GROUP_DECL(SIOPWRGD1, AB15); ++GROUP_DECL(HVI3C12, W25, Y23); ++GROUP_DECL(HVI3C13, Y24, W21); ++GROUP_DECL(HVI3C14, AA23, AC22); ++GROUP_DECL(HVI3C15, AB22, Y21); ++GROUP_DECL(I3C4, AE20, AF19); ++GROUP_DECL(I3C5, Y22, AA20); ++GROUP_DECL(I3C6, AA22, AB20); ++GROUP_DECL(I3C7, AF18, AE19); ++GROUP_DECL(I3C8, AD20, AC20); ++GROUP_DECL(I3C9, AA21, AB21); ++GROUP_DECL(I3C10, AC19, AE18); ++GROUP_DECL(I3C11, AD19, AD18); ++GROUP_DECL(HVI3C0, U25, U26); ++GROUP_DECL(HVI3C1, Y26, AA24); ++GROUP_DECL(HVI3C2, R25, AA26); ++GROUP_DECL(HVI3C3, R26, Y25); ++GROUP_DECL(LTPI, U25, U26, Y26, AA24); ++GROUP_DECL(SPI0, D24, B23, B22); ++GROUP_DECL(QSPI0, C23, B18); ++GROUP_DECL(SPI0CS1, B21); ++GROUP_DECL(SPI0ABR, M15); ++GROUP_DECL(SPI0WPN, B19); ++GROUP_DECL(SPI1, B26, A25, A24); ++GROUP_DECL(QSPI1, B24, E26); ++GROUP_DECL(SPI1CS1, A21); ++GROUP_DECL(SPI1ABR, A19); ++GROUP_DECL(SPI1WPN, A18); ++GROUP_DECL(SPI2, D26, C26, A23, A22); ++GROUP_DECL(QSPI2, B25, F26); ++GROUP_DECL(SPI2CS1, A26); ++GROUP_DECL(THRU2, A19, A18); ++GROUP_DECL(THRU3, B25, F26); ++GROUP_DECL(JTAGM1, D12, F10, E11, F11, F13); ++GROUP_DECL(MDIO0, B9, M14); ++GROUP_DECL(MDIO1, C9, C10); ++GROUP_DECL(MDIO2, E10, E13); ++GROUP_DECL(FWQSPI, M16, A15); ++GROUP_DECL(FWSPIABR, A14); ++GROUP_DECL(FWSPIWPN, N15); ++GROUP_DECL(RGMII0, C20, C19, A8, R14, A7, P14, D20, A6, B6, N14, B7, B8); ++GROUP_DECL(RGMII1, D19, B11, D15, B12, B10, P13, C18, C6, C7, D7, N13, C8); ++GROUP_DECL(RMII0, C20, A8, R14, A7, P14, A6, B6, N14); ++GROUP_DECL(RMII0RCLKO, D20); ++GROUP_DECL(RMII1, D19, D15, B12, B10, P13, C6, C7, D7); ++GROUP_DECL(RMII1RCLKO, C18); ++GROUP_DECL(VGA, J11, E7); ++GROUP_DECL(DSGPM0, D19, B10, C7, D7); ++GROUP_DECL(SGPS, B11, C18, N13, C8); ++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(USBUART, G10, K12); ++GROUP_DECL(HBLED, V24); ++GROUP_DECL(MACLINK0, U21); ++GROUP_DECL(MACLINK1, AC24); ++GROUP_DECL(MACLINK2, T24); ++GROUP_DECL(NCTS2, U21); ++GROUP_DECL(NDCD2, T24); ++GROUP_DECL(NDSR2, V22); ++GROUP_DECL(NRI2, T23); ++GROUP_DECL(NDTR2, AC25); ++GROUP_DECL(NRTS2, AB25); ++GROUP_DECL(SMON0, U21, T24, V22, T23); ++GROUP_DECL(SMON1, AB24, W26, AC25, AB25); ++GROUP_DECL(SGMII, SGMII0); ++//PCIE RC PERST ++GROUP_DECL(PE2SGRSTN, PCIERC2_PERST, E10); ++GROUP_DECL(USB2CUD, PORTC_MODE); ++GROUP_DECL(USB2CD, PORTC_MODE); ++GROUP_DECL(USB2CH, PORTC_MODE); ++GROUP_DECL(USB2CU, PORTC_MODE); ++GROUP_DECL(USB2DD, PORTD_MODE); ++GROUP_DECL(USB2DH, PORTD_MODE); + -+static void aspeed_disp_intf_remove(struct platform_device *pdev) -+{ -+ struct aspeed_disp_intf *intf = platform_get_drvdata(pdev); ++static struct aspeed_pin_group aspeed_g7_soc1_pingroups[] = { ++ ASPEED_PINCTRL_GROUP(ESPI0), ++ ASPEED_PINCTRL_GROUP(ESPI1), ++ ASPEED_PINCTRL_GROUP(LPC0), ++ ASPEED_PINCTRL_GROUP(LPC1), ++ ASPEED_PINCTRL_GROUP(SD), ++ ASPEED_PINCTRL_GROUP(VPI), ++ ASPEED_PINCTRL_GROUP(OSCCLK), ++ ASPEED_PINCTRL_GROUP(TACH0), ++ ASPEED_PINCTRL_GROUP(TACH1), ++ ASPEED_PINCTRL_GROUP(TACH2), ++ ASPEED_PINCTRL_GROUP(TACH3), ++ ASPEED_PINCTRL_GROUP(THRU0), ++ ASPEED_PINCTRL_GROUP(THRU1), ++ ASPEED_PINCTRL_GROUP(TACH4), ++ ASPEED_PINCTRL_GROUP(TACH5), ++ ASPEED_PINCTRL_GROUP(TACH6), ++ ASPEED_PINCTRL_GROUP(TACH7), ++ ASPEED_PINCTRL_GROUP(NTCS5), ++ ASPEED_PINCTRL_GROUP(NDCD5), ++ ASPEED_PINCTRL_GROUP(NDSR5), ++ ASPEED_PINCTRL_GROUP(NRI5), ++ ASPEED_PINCTRL_GROUP(SALT12), ++ ASPEED_PINCTRL_GROUP(SALT13), ++ ASPEED_PINCTRL_GROUP(SALT14), ++ ASPEED_PINCTRL_GROUP(SALT15), ++ ASPEED_PINCTRL_GROUP(NDTR5), ++ ASPEED_PINCTRL_GROUP(NRTS5), ++ ASPEED_PINCTRL_GROUP(NCTS6), ++ ASPEED_PINCTRL_GROUP(NDCD6), ++ ASPEED_PINCTRL_GROUP(NDSR6), ++ ASPEED_PINCTRL_GROUP(NRI6), ++ ASPEED_PINCTRL_GROUP(NDTR6), ++ ASPEED_PINCTRL_GROUP(NRTS6), ++ ASPEED_PINCTRL_GROUP(TACH8), ++ ASPEED_PINCTRL_GROUP(TACH9), ++ ASPEED_PINCTRL_GROUP(TACH10), ++ ASPEED_PINCTRL_GROUP(TACH11), ++ ASPEED_PINCTRL_GROUP(TACH12), ++ ASPEED_PINCTRL_GROUP(TACH13), ++ ASPEED_PINCTRL_GROUP(TACH14), ++ ASPEED_PINCTRL_GROUP(TACH15), ++ ASPEED_PINCTRL_GROUP(SPIM0), ++ ASPEED_PINCTRL_GROUP(PWM0), ++ ASPEED_PINCTRL_GROUP(PWM1), ++ ASPEED_PINCTRL_GROUP(PWM2), ++ ASPEED_PINCTRL_GROUP(PWM3), ++ ASPEED_PINCTRL_GROUP(PWM4), ++ ASPEED_PINCTRL_GROUP(PWM5), ++ ASPEED_PINCTRL_GROUP(PWM6), ++ ASPEED_PINCTRL_GROUP(PWM7), ++ ASPEED_PINCTRL_GROUP(SIOPBON0), ++ ASPEED_PINCTRL_GROUP(SIOPBIN0), ++ ASPEED_PINCTRL_GROUP(SIOSCIN0), ++ ASPEED_PINCTRL_GROUP(SIOS3N0), ++ ASPEED_PINCTRL_GROUP(SIOS5N0), ++ ASPEED_PINCTRL_GROUP(SIOPWREQN0), ++ ASPEED_PINCTRL_GROUP(SIOONCTRLN0), ++ ASPEED_PINCTRL_GROUP(SIOPWRGD0), ++ ASPEED_PINCTRL_GROUP(NCTS0), ++ ASPEED_PINCTRL_GROUP(NDCD0), ++ ASPEED_PINCTRL_GROUP(NDSR0), ++ ASPEED_PINCTRL_GROUP(NRI0), ++ ASPEED_PINCTRL_GROUP(NDTR0), ++ ASPEED_PINCTRL_GROUP(NRTS0), ++ ASPEED_PINCTRL_GROUP(TXD0), ++ ASPEED_PINCTRL_GROUP(RXD0), ++ ASPEED_PINCTRL_GROUP(NCTS1), ++ ASPEED_PINCTRL_GROUP(NDCD1), ++ ASPEED_PINCTRL_GROUP(NDSR1), ++ ASPEED_PINCTRL_GROUP(NRI1), ++ ASPEED_PINCTRL_GROUP(NDTR1), ++ ASPEED_PINCTRL_GROUP(NRTS1), ++ ASPEED_PINCTRL_GROUP(TXD1), ++ ASPEED_PINCTRL_GROUP(RXD1), ++ ASPEED_PINCTRL_GROUP(TXD2), ++ ASPEED_PINCTRL_GROUP(RXD2), ++ ASPEED_PINCTRL_GROUP(TXD3), ++ ASPEED_PINCTRL_GROUP(RXD3), ++ ASPEED_PINCTRL_GROUP(NCTS5), ++ ASPEED_PINCTRL_GROUP(NDCD5), ++ ASPEED_PINCTRL_GROUP(NDSR5), ++ ASPEED_PINCTRL_GROUP(NRI5), ++ ASPEED_PINCTRL_GROUP(NDTR5), ++ ASPEED_PINCTRL_GROUP(NRTS5), ++ ASPEED_PINCTRL_GROUP(TXD5), ++ ASPEED_PINCTRL_GROUP(RXD5), ++ ASPEED_PINCTRL_GROUP(NCTS6), ++ ASPEED_PINCTRL_GROUP(NDCD6), ++ ASPEED_PINCTRL_GROUP(NDSR6), ++ ASPEED_PINCTRL_GROUP(NRI6), ++ ASPEED_PINCTRL_GROUP(NDTR6), ++ ASPEED_PINCTRL_GROUP(NRTS6), ++ ASPEED_PINCTRL_GROUP(TXD6), ++ ASPEED_PINCTRL_GROUP(RXD6), ++ ASPEED_PINCTRL_GROUP(TXD6), ++ ASPEED_PINCTRL_GROUP(RXD6), ++ ASPEED_PINCTRL_GROUP(TXD7), ++ ASPEED_PINCTRL_GROUP(RXD7), ++ ASPEED_PINCTRL_GROUP(TXD8), ++ ASPEED_PINCTRL_GROUP(RXD8), ++ ASPEED_PINCTRL_GROUP(TXD9), ++ ASPEED_PINCTRL_GROUP(RXD9), ++ ASPEED_PINCTRL_GROUP(TXD10), ++ ASPEED_PINCTRL_GROUP(RXD10), ++ ASPEED_PINCTRL_GROUP(TXD11), ++ ASPEED_PINCTRL_GROUP(RXD11), ++ ASPEED_PINCTRL_GROUP(SPIM1), ++ ASPEED_PINCTRL_GROUP(WDTRST0N), ++ ASPEED_PINCTRL_GROUP(WDTRST1N), ++ ASPEED_PINCTRL_GROUP(WDTRST2N), ++ ASPEED_PINCTRL_GROUP(WDTRST3N), ++ ASPEED_PINCTRL_GROUP(WDTRST4N), ++ ASPEED_PINCTRL_GROUP(WDTRST5N), ++ ASPEED_PINCTRL_GROUP(WDTRST6N), ++ ASPEED_PINCTRL_GROUP(WDTRST7N), ++ ASPEED_PINCTRL_GROUP(PWM8), ++ ASPEED_PINCTRL_GROUP(PWM9), ++ ASPEED_PINCTRL_GROUP(PWM10), ++ ASPEED_PINCTRL_GROUP(PWM11), ++ ASPEED_PINCTRL_GROUP(PWM12), ++ ASPEED_PINCTRL_GROUP(PWM13), ++ ASPEED_PINCTRL_GROUP(PWM14), ++ ASPEED_PINCTRL_GROUP(PWM15), ++ ASPEED_PINCTRL_GROUP(SALT0), ++ ASPEED_PINCTRL_GROUP(SALT1), ++ ASPEED_PINCTRL_GROUP(SALT2), ++ ASPEED_PINCTRL_GROUP(SALT3), ++ ASPEED_PINCTRL_GROUP(FSI0), ++ ASPEED_PINCTRL_GROUP(FSI1), ++ ASPEED_PINCTRL_GROUP(FSI2), ++ ASPEED_PINCTRL_GROUP(FSI3), ++ ASPEED_PINCTRL_GROUP(SPIM2), ++ ASPEED_PINCTRL_GROUP(SALT4), ++ ASPEED_PINCTRL_GROUP(SALT5), ++ ASPEED_PINCTRL_GROUP(SALT6), ++ ASPEED_PINCTRL_GROUP(SALT7), ++ ASPEED_PINCTRL_GROUP(SALT8), ++ ASPEED_PINCTRL_GROUP(SALT9), ++ ASPEED_PINCTRL_GROUP(SALT10), ++ ASPEED_PINCTRL_GROUP(SALT11), ++ ASPEED_PINCTRL_GROUP(ADC0), ++ ASPEED_PINCTRL_GROUP(ADC1), ++ ASPEED_PINCTRL_GROUP(ADC2), ++ ASPEED_PINCTRL_GROUP(ADC3), ++ ASPEED_PINCTRL_GROUP(ADC4), ++ ASPEED_PINCTRL_GROUP(ADC5), ++ ASPEED_PINCTRL_GROUP(ADC6), ++ ASPEED_PINCTRL_GROUP(ADC7), ++ ASPEED_PINCTRL_GROUP(ADC8), ++ ASPEED_PINCTRL_GROUP(ADC9), ++ ASPEED_PINCTRL_GROUP(ADC10), ++ ASPEED_PINCTRL_GROUP(ADC11), ++ ASPEED_PINCTRL_GROUP(ADC12), ++ ASPEED_PINCTRL_GROUP(ADC13), ++ ASPEED_PINCTRL_GROUP(ADC14), ++ ASPEED_PINCTRL_GROUP(ADC15), ++ ASPEED_PINCTRL_GROUP(AUXPWRGOOD0), ++ ASPEED_PINCTRL_GROUP(AUXPWRGOOD1), ++ ASPEED_PINCTRL_GROUP(SGPM0), ++ ASPEED_PINCTRL_GROUP(SGPM1), ++ ASPEED_PINCTRL_GROUP(I2C0), ++ ASPEED_PINCTRL_GROUP(I2C1), ++ ASPEED_PINCTRL_GROUP(I2C2), ++ ASPEED_PINCTRL_GROUP(I2C3), ++ ASPEED_PINCTRL_GROUP(I2C4), ++ ASPEED_PINCTRL_GROUP(I2C5), ++ ASPEED_PINCTRL_GROUP(I2C6), ++ ASPEED_PINCTRL_GROUP(I2C7), ++ ASPEED_PINCTRL_GROUP(I2C8), ++ ASPEED_PINCTRL_GROUP(I2C9), ++ ASPEED_PINCTRL_GROUP(I2C10), ++ ASPEED_PINCTRL_GROUP(I2C11), ++ ASPEED_PINCTRL_GROUP(I2C12), ++ ASPEED_PINCTRL_GROUP(I2C13), ++ ASPEED_PINCTRL_GROUP(I2C14), ++ ASPEED_PINCTRL_GROUP(I2C15), ++ ASPEED_PINCTRL_GROUP(LTPI_PS_I2C0), ++ ASPEED_PINCTRL_GROUP(LTPI_PS_I2C1), ++ ASPEED_PINCTRL_GROUP(LTPI_PS_I2C2), ++ ASPEED_PINCTRL_GROUP(LTPI_PS_I2C3), ++ ASPEED_PINCTRL_GROUP(DI2C0), ++ ASPEED_PINCTRL_GROUP(DI2C1), ++ ASPEED_PINCTRL_GROUP(DI2C2), ++ ASPEED_PINCTRL_GROUP(DI2C3), ++ ASPEED_PINCTRL_GROUP(DI2C8), ++ ASPEED_PINCTRL_GROUP(DI2C9), ++ ASPEED_PINCTRL_GROUP(DI2C10), ++ ASPEED_PINCTRL_GROUP(DI2C11), ++ ASPEED_PINCTRL_GROUP(DI2C12), ++ ASPEED_PINCTRL_GROUP(DI2C13), ++ ASPEED_PINCTRL_GROUP(DI2C14), ++ ASPEED_PINCTRL_GROUP(DI2C15), ++ ASPEED_PINCTRL_GROUP(SIOPBON1), ++ ASPEED_PINCTRL_GROUP(SIOPBIN1), ++ ASPEED_PINCTRL_GROUP(SIOSCIN1), ++ ASPEED_PINCTRL_GROUP(SIOS3N1), ++ ASPEED_PINCTRL_GROUP(SIOS5N1), ++ ASPEED_PINCTRL_GROUP(SIOPWREQN1), ++ ASPEED_PINCTRL_GROUP(SIOONCTRLN1), ++ ASPEED_PINCTRL_GROUP(SIOPWRGD1), ++ ASPEED_PINCTRL_GROUP(HVI3C12), ++ ASPEED_PINCTRL_GROUP(HVI3C13), ++ ASPEED_PINCTRL_GROUP(HVI3C14), ++ ASPEED_PINCTRL_GROUP(HVI3C15), ++ ASPEED_PINCTRL_GROUP(I3C4), ++ ASPEED_PINCTRL_GROUP(I3C5), ++ ASPEED_PINCTRL_GROUP(I3C6), ++ ASPEED_PINCTRL_GROUP(I3C7), ++ ASPEED_PINCTRL_GROUP(I3C8), ++ ASPEED_PINCTRL_GROUP(I3C9), ++ ASPEED_PINCTRL_GROUP(I3C10), ++ ASPEED_PINCTRL_GROUP(I3C11), ++ ASPEED_PINCTRL_GROUP(HVI3C0), ++ ASPEED_PINCTRL_GROUP(HVI3C1), ++ ASPEED_PINCTRL_GROUP(HVI3C2), ++ ASPEED_PINCTRL_GROUP(HVI3C3), ++ ASPEED_PINCTRL_GROUP(LTPI), ++ ASPEED_PINCTRL_GROUP(SPI0), ++ ASPEED_PINCTRL_GROUP(QSPI0), ++ ASPEED_PINCTRL_GROUP(SPI0CS1), ++ ASPEED_PINCTRL_GROUP(SPI0ABR), ++ ASPEED_PINCTRL_GROUP(SPI0WPN), ++ ASPEED_PINCTRL_GROUP(SPI1), ++ ASPEED_PINCTRL_GROUP(QSPI1), ++ ASPEED_PINCTRL_GROUP(SPI1CS1), ++ ASPEED_PINCTRL_GROUP(SPI1ABR), ++ ASPEED_PINCTRL_GROUP(SPI1WPN), ++ ASPEED_PINCTRL_GROUP(SPI2), ++ ASPEED_PINCTRL_GROUP(QSPI2), ++ ASPEED_PINCTRL_GROUP(SPI2CS1), ++ ASPEED_PINCTRL_GROUP(THRU2), ++ ASPEED_PINCTRL_GROUP(THRU3), ++ ASPEED_PINCTRL_GROUP(JTAGM1), ++ ASPEED_PINCTRL_GROUP(MDIO0), ++ ASPEED_PINCTRL_GROUP(MDIO1), ++ ASPEED_PINCTRL_GROUP(MDIO2), ++ ASPEED_PINCTRL_GROUP(FWQSPI), ++ ASPEED_PINCTRL_GROUP(FWSPIABR), ++ ASPEED_PINCTRL_GROUP(FWSPIWPN), ++ ASPEED_PINCTRL_GROUP(RGMII0), ++ ASPEED_PINCTRL_GROUP(RGMII1), ++ ASPEED_PINCTRL_GROUP(RMII0), ++ ASPEED_PINCTRL_GROUP(RMII0RCLKO), ++ ASPEED_PINCTRL_GROUP(RMII1), ++ ASPEED_PINCTRL_GROUP(RMII1RCLKO), ++ ASPEED_PINCTRL_GROUP(VGA), ++ ASPEED_PINCTRL_GROUP(DSGPM0), ++ ASPEED_PINCTRL_GROUP(SGPS), ++ ASPEED_PINCTRL_GROUP(I2CF0), ++ ASPEED_PINCTRL_GROUP(I2CF1), ++ ASPEED_PINCTRL_GROUP(I2CF2), ++ ASPEED_PINCTRL_GROUP(CANBUS), ++ ASPEED_PINCTRL_GROUP(USBUART), ++ ASPEED_PINCTRL_GROUP(HBLED), ++ ASPEED_PINCTRL_GROUP(MACLINK0), ++ ASPEED_PINCTRL_GROUP(MACLINK1), ++ ASPEED_PINCTRL_GROUP(MACLINK2), ++ ASPEED_PINCTRL_GROUP(NCTS2), ++ ASPEED_PINCTRL_GROUP(NDCD2), ++ ASPEED_PINCTRL_GROUP(NDSR2), ++ ASPEED_PINCTRL_GROUP(NRI2), ++ ASPEED_PINCTRL_GROUP(NDTR2), ++ ASPEED_PINCTRL_GROUP(NRTS2), ++ ASPEED_PINCTRL_GROUP(SMON0), ++ ASPEED_PINCTRL_GROUP(SMON1), ++ ASPEED_PINCTRL_GROUP(SGMII), ++ ASPEED_PINCTRL_GROUP(PE2SGRSTN), ++ ASPEED_PINCTRL_GROUP(USB2CUD), ++ ASPEED_PINCTRL_GROUP(USB2CD), ++ ASPEED_PINCTRL_GROUP(USB2CH), ++ ASPEED_PINCTRL_GROUP(USB2CU), ++ ASPEED_PINCTRL_GROUP(USB2DD), ++ ASPEED_PINCTRL_GROUP(USB2DH), ++}; + -+ sysfs_remove_group(&intf->dev->kobj, &aspeed_disp_intf_attgrp); -+ misc_deregister(&intf->miscdev); -+ devm_kfree(&pdev->dev, intf); -+} ++FUNC_DECL_(ESPI0, "ESPI0"); ++FUNC_DECL_(ESPI1, "ESPI1"); ++FUNC_DECL_(LPC0, "LPC0"); ++FUNC_DECL_(LPC1, "LPC1"); ++FUNC_DECL_(VPI, "VPI"); ++FUNC_DECL_(SD, "SD"); ++FUNC_DECL_(OSCCLK, "OSCCLK"); ++FUNC_DECL_(TACH0, "TACH0"); ++FUNC_DECL_(TACH1, "TACH1"); ++FUNC_DECL_(TACH2, "TACH2"); ++FUNC_DECL_(TACH3, "TACH3"); ++FUNC_DECL_(TACH4, "TACH4"); ++FUNC_DECL_(TACH5, "TACH5"); ++FUNC_DECL_(TACH6, "TACH6"); ++FUNC_DECL_(TACH7, "TACH7"); ++FUNC_DECL_(THRU0, "THRU0"); ++FUNC_DECL_(THRU1, "THRU1"); ++FUNC_DECL_(NTCS5, "NTCS5"); ++FUNC_DECL_(NDSR5, "NDSR5"); ++FUNC_DECL_(NRI5, "NRI5"); ++FUNC_DECL_(TACH8, "TACH8"); ++FUNC_DECL_(TACH9, "TACH9"); ++FUNC_DECL_(TACH10, "TACH10"); ++FUNC_DECL_(TACH11, "TACH11"); ++FUNC_DECL_(TACH12, "TACH12"); ++FUNC_DECL_(TACH13, "TACH13"); ++FUNC_DECL_(TACH14, "TACH14"); ++FUNC_DECL_(TACH15, "TACH15"); ++FUNC_DECL_(SALT12, "SALT12"); ++FUNC_DECL_(SALT13, "SALT13"); ++FUNC_DECL_(SALT14, "SALT14"); ++FUNC_DECL_(SALT15, "SALT15"); ++FUNC_DECL_(SPIM0, "SPIM0"); ++FUNC_DECL_(PWM0, "PWM0"); ++FUNC_DECL_(PWM1, "PWM1"); ++FUNC_DECL_(PWM2, "PWM2"); ++FUNC_DECL_(PWM3, "PWM3"); ++FUNC_DECL_(PWM4, "PWM4"); ++FUNC_DECL_(PWM5, "PWM5"); ++FUNC_DECL_(PWM6, "PWM6"); ++FUNC_DECL_(PWM7, "PWM7"); ++FUNC_DECL_(SIOPBON0, "SIOPBON0"); ++FUNC_DECL_(SIOPBIN0, "SIOPBIN0"); ++FUNC_DECL_(SIOSCIN0, "SIOSCIN0"); ++FUNC_DECL_(SIOS3N0, "SIOS3N0"); ++FUNC_DECL_(SIOS5N0, "SIOS5N0"); ++FUNC_DECL_(SIOPWREQN0, "SIOPWREQN0"); ++FUNC_DECL_(SIOONCTRLN0, "SIOONCTRLN0"); ++FUNC_DECL_(SIOPWRGD0, "SIOPWRGD0"); ++FUNC_DECL_(UART0, "NCTS0", "NDCD0", "NDSR0", "NRI0", "NDTR0", "NRTS0", "TXD0", "RXD0"); ++FUNC_DECL_(UART1, "NCTS1", "NDCD1", "NDSR1", "NRI1", "NDTR1", "NRTS1", "TXD1", "RXD1"); ++FUNC_DECL_(UART2, "TXD2", "RXD2"); ++FUNC_DECL_(UART3, "TXD3", "RXD3"); ++FUNC_DECL_(UART5, "NCTS5", "NDCD5", "NDSR5", "NRI5", "NDTR5", "NRTS5", "TXD5", "RXD5"); ++FUNC_DECL_(UART6, "NCTS6", "NDCD6", "NDSR6", "NRI6", "NDTR6", "NRTS6", "TXD6", "RXD6"); ++FUNC_DECL_(UART7, "TXD7", "RXD7"); ++FUNC_DECL_(UART8, "TXD8", "RXD8"); ++FUNC_DECL_(UART9, "TXD9", "RXD9"); ++FUNC_DECL_(UART10, "TXD10", "RXD10"); ++FUNC_DECL_(UART11, "TXD11", "RXD11"); ++FUNC_DECL_(SPIM1, "SPIM1"); ++FUNC_DECL_(SPIM2, "SPIM2"); ++FUNC_DECL_(PWM8, "PWM8"); ++FUNC_DECL_(PWM9, "PWM9"); ++FUNC_DECL_(PWM10, "PWM10"); ++FUNC_DECL_(PWM11, "PWM11"); ++FUNC_DECL_(PWM12, "PWM12"); ++FUNC_DECL_(PWM13, "PWM13"); ++FUNC_DECL_(PWM14, "PWM14"); ++FUNC_DECL_(PWM15, "PWM15"); ++FUNC_DECL_(WDTRST0N, "WDTRST0N"); ++FUNC_DECL_(WDTRST1N, "WDTRST1N"); ++FUNC_DECL_(WDTRST2N, "WDTRST2N"); ++FUNC_DECL_(WDTRST3N, "WDTRST3N"); ++FUNC_DECL_(WDTRST4N, "WDTRST4N"); ++FUNC_DECL_(WDTRST5N, "WDTRST5N"); ++FUNC_DECL_(WDTRST6N, "WDTRST6N"); ++FUNC_DECL_(WDTRST7N, "WDTRST7N"); ++FUNC_DECL_(FSI0, "FSI0"); ++FUNC_DECL_(FSI1, "FSI1"); ++FUNC_DECL_(FSI2, "FSI2"); ++FUNC_DECL_(FSI3, "FSI3"); ++FUNC_DECL_(SALT0, "SALT0"); ++FUNC_DECL_(SALT1, "SALT1"); ++FUNC_DECL_(SALT2, "SALT2"); ++FUNC_DECL_(SALT3, "SALT3"); ++FUNC_DECL_(SALT4, "SALT4"); ++FUNC_DECL_(SALT5, "SALT5"); ++FUNC_DECL_(SALT6, "SALT6"); ++FUNC_DECL_(SALT7, "SALT7"); ++FUNC_DECL_(SALT8, "SALT8"); ++FUNC_DECL_(SALT9, "SALT9"); ++FUNC_DECL_(SALT10, "SALT10"); ++FUNC_DECL_(SALT11, "SALT11"); ++FUNC_DECL_(ADC0, "ADC0"); ++FUNC_DECL_(ADC1, "ADC1"); ++FUNC_DECL_(ADC2, "ADC2"); ++FUNC_DECL_(ADC3, "ADC3"); ++FUNC_DECL_(ADC4, "ADC4"); ++FUNC_DECL_(ADC5, "ADC5"); ++FUNC_DECL_(ADC6, "ADC6"); ++FUNC_DECL_(ADC7, "ADC7"); ++FUNC_DECL_(ADC8, "ADC8"); ++FUNC_DECL_(ADC9, "ADC9"); ++FUNC_DECL_(ADC10, "ADC10"); ++FUNC_DECL_(ADC11, "ADC11"); ++FUNC_DECL_(ADC12, "ADC12"); ++FUNC_DECL_(ADC13, "ADC13"); ++FUNC_DECL_(ADC14, "ADC14"); ++FUNC_DECL_(ADC15, "ADC15"); ++FUNC_DECL_(AUXPWRGOOD0, "AUXPWRGOOD0"); ++FUNC_DECL_(AUXPWRGOOD1, "AUXPWRGOOD1"); ++FUNC_DECL_(SGPM0, "SGPM0", "DSGPM0"); ++FUNC_DECL_(SGPM1, "SGPM1"); ++FUNC_DECL_(LTPI_PS_I2C0, "LTPI_PS_I2C0"); ++FUNC_DECL_(LTPI_PS_I2C1, "LTPI_PS_I2C1"); ++FUNC_DECL_(LTPI_PS_I2C2, "LTPI_PS_I2C2"); ++FUNC_DECL_(LTPI_PS_I2C3, "LTPI_PS_I2C3"); ++FUNC_DECL_(I2C0, "I2C0", "DI2C0"); ++FUNC_DECL_(I2C1, "I2C1", "DI2C1"); ++FUNC_DECL_(I2C2, "I2C2", "DI2C2"); ++FUNC_DECL_(I2C3, "I2C3", "DI2C3"); ++FUNC_DECL_(I2C4, "I2C4"); ++FUNC_DECL_(I2C5, "I2C5"); ++FUNC_DECL_(I2C6, "I2C6"); ++FUNC_DECL_(I2C7, "I2C7"); ++FUNC_DECL_(I2C8, "I2C8", "DI2C8"); ++FUNC_DECL_(I2C9, "I2C9", "DI2C9"); ++FUNC_DECL_(I2C10, "I2C10", "DI2C10"); ++FUNC_DECL_(I2C11, "I2C11", "DI2C11"); ++FUNC_DECL_(I2C12, "I2C12", "DI2C12"); ++FUNC_DECL_(I2C13, "I2C13", "DI2C13"); ++FUNC_DECL_(I2C14, "I2C14", "DI2C14"); ++FUNC_DECL_(I2C15, "I2C15", "DI2C15"); ++FUNC_DECL_(SIOPBON1, "SIOPBON1"); ++FUNC_DECL_(SIOPBIN1, "SIOPBIN1"); ++FUNC_DECL_(SIOSCIN1, "SIOSCIN1"); ++FUNC_DECL_(SIOS3N1, "SIOS3N1"); ++FUNC_DECL_(SIOS5N1, "SIOS5N1"); ++FUNC_DECL_(SIOPWREQN1, "SIOPWREQN1"); ++FUNC_DECL_(SIOONCTRLN1, "SIOONCTRLN1"); ++FUNC_DECL_(SIOPWRGD1, "SIOPWRGD1"); ++FUNC_DECL_(I3C0, "HVI3C0"); ++FUNC_DECL_(I3C1, "HVI3C1"); ++FUNC_DECL_(I3C2, "HVI3C2"); ++FUNC_DECL_(I3C3, "HVI3C3"); ++FUNC_DECL_(I3C4, "I3C4"); ++FUNC_DECL_(I3C5, "I3C5"); ++FUNC_DECL_(I3C6, "I3C6"); ++FUNC_DECL_(I3C7, "I3C7"); ++FUNC_DECL_(I3C8, "I3C8"); ++FUNC_DECL_(I3C9, "I3C9"); ++FUNC_DECL_(I3C10, "I3C10"); ++FUNC_DECL_(I3C11, "I3C11"); ++FUNC_DECL_(I3C12, "HVI3C12"); ++FUNC_DECL_(I3C13, "HVI3C13"); ++FUNC_DECL_(I3C14, "HVI3C14"); ++FUNC_DECL_(I3C15, "HVI3C15"); ++FUNC_DECL_(LTPI, "LTPI"); ++FUNC_DECL_(SPI0, "SPI0"); ++FUNC_DECL_(QSPI0, "QSPI0"); ++FUNC_DECL_(SPI0CS1, "SPI0CS1"); ++FUNC_DECL_(SPI0ABR, "SPI0ABR"); ++FUNC_DECL_(SPI0WPN, "SPI0WPN"); ++FUNC_DECL_(SPI1, "SPI1"); ++FUNC_DECL_(QSPI1, "QSPI1"); ++FUNC_DECL_(SPI1CS1, "SPI1CS1"); ++FUNC_DECL_(SPI1ABR, "SPI1ABR"); ++FUNC_DECL_(SPI1WPN, "SPI1WPN"); ++FUNC_DECL_(SPI2, "SPI2"); ++FUNC_DECL_(QSPI2, "QSPI2"); ++FUNC_DECL_(SPI2CS1, "SPI2CS1"); ++FUNC_DECL_(THRU2, "THRU2"); ++FUNC_DECL_(THRU3, "THRU3"); ++FUNC_DECL_(JTAGM1, "JTAGM1"); ++FUNC_DECL_(MDIO0, "MDIO0"); ++FUNC_DECL_(MDIO1, "MDIO1"); ++FUNC_DECL_(MDIO2, "MDIO2"); ++FUNC_DECL_(FWQSPI, "FWQSPI"); ++FUNC_DECL_(FWSPIABR, "FWSPIABR"); ++FUNC_DECL_(FWSPIWPN, "FWSPIWPN"); ++FUNC_DECL_(RGMII0, "RGMII0"); ++FUNC_DECL_(RGMII1, "RGMII1"); ++FUNC_DECL_(RMII0, "RMII0"); ++FUNC_DECL_(RMII0RCLKO, "RMII0RCLKO"); ++FUNC_DECL_(RMII1, "RMII1"); ++FUNC_DECL_(RMII1RCLKO, "RMII1RCLKO"); ++FUNC_DECL_(VGA, "VGA"); ++FUNC_DECL_(SGPS, "SGPS"); ++FUNC_DECL_(I2CF0, "I2CF0"); ++FUNC_DECL_(I2CF1, "I2CF1"); ++FUNC_DECL_(I2CF2, "I2CF2"); ++FUNC_DECL_(CANBUS, "CANBUS"); ++FUNC_DECL_(USBUART, "USBUART"); ++FUNC_DECL_(HBLED, "HBLED"); ++FUNC_DECL_(MACLINK0, "MACLINK0"); ++FUNC_DECL_(MACLINK1, "MACLINK1"); ++FUNC_DECL_(MACLINK2, "MACLINK2"); ++FUNC_DECL_(SMON0, "SMON0"); ++FUNC_DECL_(SMON1, "SMON1"); ++FUNC_DECL_(SGMII, "SGMII"); ++FUNC_DECL_(PCIERC, "PE2SGRSTN"); ++FUNC_DECL_(USB2C, "USB2CUD", "USB2CD", "USB2CH", "USB2CU"); ++FUNC_DECL_(USB2D, "USB2DD", "USB2DH"); + -+static const struct of_device_id aspeed_disp_intf_of_matches[] = { -+ { .compatible = "aspeed,ast2600-disp-intf", .data = &ast2600_config }, -+ { .compatible = "aspeed,ast2700-disp-intf", .data = &ast2700_config }, -+ {}, ++static struct aspeed_pin_function aspeed_g7_soc1_funcs[] = { ++ ASPEED_PINCTRL_FUNC(ESPI0), ++ ASPEED_PINCTRL_FUNC(ESPI1), ++ ASPEED_PINCTRL_FUNC(LPC0), ++ ASPEED_PINCTRL_FUNC(LPC1), ++ ASPEED_PINCTRL_FUNC(VPI), ++ ASPEED_PINCTRL_FUNC(SD), ++ ASPEED_PINCTRL_FUNC(OSCCLK), ++ ASPEED_PINCTRL_FUNC(TACH0), ++ ASPEED_PINCTRL_FUNC(TACH1), ++ ASPEED_PINCTRL_FUNC(TACH2), ++ ASPEED_PINCTRL_FUNC(TACH3), ++ ASPEED_PINCTRL_FUNC(TACH4), ++ ASPEED_PINCTRL_FUNC(TACH5), ++ ASPEED_PINCTRL_FUNC(TACH6), ++ ASPEED_PINCTRL_FUNC(TACH7), ++ ASPEED_PINCTRL_FUNC(THRU0), ++ ASPEED_PINCTRL_FUNC(THRU1), ++ ASPEED_PINCTRL_FUNC(NTCS5), ++ ASPEED_PINCTRL_FUNC(NTCS5), ++ ASPEED_PINCTRL_FUNC(NDSR5), ++ ASPEED_PINCTRL_FUNC(NRI5), ++ ASPEED_PINCTRL_FUNC(NRI5), ++ ASPEED_PINCTRL_FUNC(SALT12), ++ ASPEED_PINCTRL_FUNC(SALT13), ++ ASPEED_PINCTRL_FUNC(SALT14), ++ ASPEED_PINCTRL_FUNC(SALT15), ++ ASPEED_PINCTRL_FUNC(TACH8), ++ ASPEED_PINCTRL_FUNC(TACH9), ++ ASPEED_PINCTRL_FUNC(TACH10), ++ ASPEED_PINCTRL_FUNC(TACH11), ++ ASPEED_PINCTRL_FUNC(TACH12), ++ ASPEED_PINCTRL_FUNC(TACH13), ++ ASPEED_PINCTRL_FUNC(TACH14), ++ ASPEED_PINCTRL_FUNC(TACH15), ++ ASPEED_PINCTRL_FUNC(SPIM0), ++ ASPEED_PINCTRL_FUNC(PWM0), ++ ASPEED_PINCTRL_FUNC(PWM1), ++ ASPEED_PINCTRL_FUNC(PWM2), ++ ASPEED_PINCTRL_FUNC(PWM3), ++ ASPEED_PINCTRL_FUNC(PWM4), ++ ASPEED_PINCTRL_FUNC(PWM5), ++ ASPEED_PINCTRL_FUNC(PWM6), ++ ASPEED_PINCTRL_FUNC(PWM7), ++ ASPEED_PINCTRL_FUNC(SIOPBON0), ++ ASPEED_PINCTRL_FUNC(SIOPBIN0), ++ ASPEED_PINCTRL_FUNC(SIOSCIN0), ++ ASPEED_PINCTRL_FUNC(SIOS3N0), ++ ASPEED_PINCTRL_FUNC(SIOS5N0), ++ ASPEED_PINCTRL_FUNC(SIOPWREQN0), ++ ASPEED_PINCTRL_FUNC(SIOONCTRLN0), ++ ASPEED_PINCTRL_FUNC(SIOPWRGD0), ++ ASPEED_PINCTRL_FUNC(UART0), ++ ASPEED_PINCTRL_FUNC(UART1), ++ ASPEED_PINCTRL_FUNC(UART2), ++ ASPEED_PINCTRL_FUNC(UART3), ++ ASPEED_PINCTRL_FUNC(UART5), ++ ASPEED_PINCTRL_FUNC(UART6), ++ ASPEED_PINCTRL_FUNC(UART7), ++ ASPEED_PINCTRL_FUNC(UART8), ++ ASPEED_PINCTRL_FUNC(UART9), ++ ASPEED_PINCTRL_FUNC(UART10), ++ ASPEED_PINCTRL_FUNC(UART11), ++ ASPEED_PINCTRL_FUNC(SPIM1), ++ ASPEED_PINCTRL_FUNC(PWM7), ++ ASPEED_PINCTRL_FUNC(PWM8), ++ ASPEED_PINCTRL_FUNC(PWM9), ++ ASPEED_PINCTRL_FUNC(PWM10), ++ ASPEED_PINCTRL_FUNC(PWM11), ++ ASPEED_PINCTRL_FUNC(PWM12), ++ ASPEED_PINCTRL_FUNC(PWM13), ++ ASPEED_PINCTRL_FUNC(PWM14), ++ ASPEED_PINCTRL_FUNC(PWM15), ++ ASPEED_PINCTRL_FUNC(WDTRST0N), ++ ASPEED_PINCTRL_FUNC(WDTRST1N), ++ ASPEED_PINCTRL_FUNC(WDTRST2N), ++ ASPEED_PINCTRL_FUNC(WDTRST3N), ++ ASPEED_PINCTRL_FUNC(WDTRST4N), ++ ASPEED_PINCTRL_FUNC(WDTRST5N), ++ ASPEED_PINCTRL_FUNC(WDTRST6N), ++ ASPEED_PINCTRL_FUNC(WDTRST7N), ++ ASPEED_PINCTRL_FUNC(FSI0), ++ ASPEED_PINCTRL_FUNC(FSI1), ++ ASPEED_PINCTRL_FUNC(FSI2), ++ ASPEED_PINCTRL_FUNC(FSI3), ++ ASPEED_PINCTRL_FUNC(SALT0), ++ ASPEED_PINCTRL_FUNC(SALT1), ++ ASPEED_PINCTRL_FUNC(SALT2), ++ ASPEED_PINCTRL_FUNC(SALT3), ++ ASPEED_PINCTRL_FUNC(SALT4), ++ ASPEED_PINCTRL_FUNC(SALT5), ++ ASPEED_PINCTRL_FUNC(SALT6), ++ ASPEED_PINCTRL_FUNC(SALT7), ++ ASPEED_PINCTRL_FUNC(SALT8), ++ ASPEED_PINCTRL_FUNC(SALT9), ++ ASPEED_PINCTRL_FUNC(SALT10), ++ ASPEED_PINCTRL_FUNC(SALT11), ++ ASPEED_PINCTRL_FUNC(ADC0), ++ ASPEED_PINCTRL_FUNC(ADC1), ++ ASPEED_PINCTRL_FUNC(ADC2), ++ ASPEED_PINCTRL_FUNC(ADC3), ++ ASPEED_PINCTRL_FUNC(ADC4), ++ ASPEED_PINCTRL_FUNC(ADC5), ++ ASPEED_PINCTRL_FUNC(ADC6), ++ ASPEED_PINCTRL_FUNC(ADC7), ++ ASPEED_PINCTRL_FUNC(ADC8), ++ ASPEED_PINCTRL_FUNC(ADC9), ++ ASPEED_PINCTRL_FUNC(ADC10), ++ ASPEED_PINCTRL_FUNC(ADC11), ++ ASPEED_PINCTRL_FUNC(ADC12), ++ ASPEED_PINCTRL_FUNC(ADC13), ++ ASPEED_PINCTRL_FUNC(ADC14), ++ ASPEED_PINCTRL_FUNC(ADC15), ++ ASPEED_PINCTRL_FUNC(AUXPWRGOOD0), ++ ASPEED_PINCTRL_FUNC(AUXPWRGOOD1), ++ ASPEED_PINCTRL_FUNC(SGPM0), ++ ASPEED_PINCTRL_FUNC(SGPM1), ++ ASPEED_PINCTRL_FUNC(SPIM2), ++ ASPEED_PINCTRL_FUNC(LTPI_PS_I2C0), ++ ASPEED_PINCTRL_FUNC(LTPI_PS_I2C1), ++ ASPEED_PINCTRL_FUNC(LTPI_PS_I2C2), ++ ASPEED_PINCTRL_FUNC(LTPI_PS_I2C3), ++ ASPEED_PINCTRL_FUNC(I2C0), ++ ASPEED_PINCTRL_FUNC(I2C1), ++ ASPEED_PINCTRL_FUNC(I2C2), ++ ASPEED_PINCTRL_FUNC(I2C3), ++ ASPEED_PINCTRL_FUNC(I2C4), ++ ASPEED_PINCTRL_FUNC(I2C5), ++ ASPEED_PINCTRL_FUNC(I2C6), ++ ASPEED_PINCTRL_FUNC(I2C7), ++ ASPEED_PINCTRL_FUNC(I2C8), ++ ASPEED_PINCTRL_FUNC(I2C9), ++ ASPEED_PINCTRL_FUNC(I2C10), ++ ASPEED_PINCTRL_FUNC(I2C11), ++ ASPEED_PINCTRL_FUNC(I2C12), ++ ASPEED_PINCTRL_FUNC(I2C13), ++ ASPEED_PINCTRL_FUNC(I2C14), ++ ASPEED_PINCTRL_FUNC(I2C15), ++ ASPEED_PINCTRL_FUNC(SIOPBON1), ++ ASPEED_PINCTRL_FUNC(SIOPBIN1), ++ ASPEED_PINCTRL_FUNC(SIOSCIN1), ++ ASPEED_PINCTRL_FUNC(SIOS3N1), ++ ASPEED_PINCTRL_FUNC(SIOS5N1), ++ ASPEED_PINCTRL_FUNC(SIOPWREQN1), ++ ASPEED_PINCTRL_FUNC(SIOONCTRLN1), ++ ASPEED_PINCTRL_FUNC(SIOPWRGD1), ++ ASPEED_PINCTRL_FUNC(I3C0), ++ ASPEED_PINCTRL_FUNC(I3C1), ++ ASPEED_PINCTRL_FUNC(I3C2), ++ ASPEED_PINCTRL_FUNC(I3C3), ++ ASPEED_PINCTRL_FUNC(I3C4), ++ ASPEED_PINCTRL_FUNC(I3C5), ++ ASPEED_PINCTRL_FUNC(I3C6), ++ ASPEED_PINCTRL_FUNC(I3C7), ++ ASPEED_PINCTRL_FUNC(I3C8), ++ ASPEED_PINCTRL_FUNC(I3C9), ++ ASPEED_PINCTRL_FUNC(I3C10), ++ ASPEED_PINCTRL_FUNC(I3C11), ++ ASPEED_PINCTRL_FUNC(I3C12), ++ ASPEED_PINCTRL_FUNC(I3C13), ++ ASPEED_PINCTRL_FUNC(I3C14), ++ ASPEED_PINCTRL_FUNC(I3C15), ++ ASPEED_PINCTRL_FUNC(LTPI), ++ ASPEED_PINCTRL_FUNC(SPI0), ++ ASPEED_PINCTRL_FUNC(QSPI0), ++ ASPEED_PINCTRL_FUNC(SPI0CS1), ++ ASPEED_PINCTRL_FUNC(SPI0ABR), ++ ASPEED_PINCTRL_FUNC(SPI0WPN), ++ ASPEED_PINCTRL_FUNC(SPI1), ++ ASPEED_PINCTRL_FUNC(QSPI1), ++ ASPEED_PINCTRL_FUNC(SPI1CS1), ++ ASPEED_PINCTRL_FUNC(SPI1ABR), ++ ASPEED_PINCTRL_FUNC(SPI1WPN), ++ ASPEED_PINCTRL_FUNC(SPI2), ++ ASPEED_PINCTRL_FUNC(QSPI2), ++ ASPEED_PINCTRL_FUNC(SPI2CS1), ++ ASPEED_PINCTRL_FUNC(THRU2), ++ ASPEED_PINCTRL_FUNC(THRU3), ++ ASPEED_PINCTRL_FUNC(JTAGM1), ++ ASPEED_PINCTRL_FUNC(MDIO0), ++ ASPEED_PINCTRL_FUNC(MDIO1), ++ ASPEED_PINCTRL_FUNC(MDIO2), ++ ASPEED_PINCTRL_FUNC(FWQSPI), ++ ASPEED_PINCTRL_FUNC(FWSPIABR), ++ ASPEED_PINCTRL_FUNC(FWSPIWPN), ++ ASPEED_PINCTRL_FUNC(RGMII0), ++ ASPEED_PINCTRL_FUNC(RGMII1), ++ ASPEED_PINCTRL_FUNC(RMII0), ++ ASPEED_PINCTRL_FUNC(RMII0RCLKO), ++ ASPEED_PINCTRL_FUNC(RMII1), ++ ASPEED_PINCTRL_FUNC(RMII1RCLKO), ++ ASPEED_PINCTRL_FUNC(VGA), ++ ASPEED_PINCTRL_FUNC(SGPS), ++ ASPEED_PINCTRL_FUNC(I2CF0), ++ ASPEED_PINCTRL_FUNC(I2CF1), ++ ASPEED_PINCTRL_FUNC(I2CF2), ++ ASPEED_PINCTRL_FUNC(CANBUS), ++ ASPEED_PINCTRL_FUNC(USBUART), ++ ASPEED_PINCTRL_FUNC(HBLED), ++ ASPEED_PINCTRL_FUNC(MACLINK0), ++ ASPEED_PINCTRL_FUNC(MACLINK1), ++ ASPEED_PINCTRL_FUNC(MACLINK2), ++ ASPEED_PINCTRL_FUNC(SMON0), ++ ASPEED_PINCTRL_FUNC(SMON1), ++ ASPEED_PINCTRL_FUNC(SGMII), ++ ASPEED_PINCTRL_FUNC(PCIERC), ++ ASPEED_PINCTRL_FUNC(USB2C), ++ ASPEED_PINCTRL_FUNC(USB2D), +}; + -+static struct platform_driver aspeed_disp_intf_driver = { -+ .probe = aspeed_disp_intf_probe, -+ .remove = aspeed_disp_intf_remove, -+ .driver = { -+ .name = DEVICE_NAME, -+ .of_match_table = aspeed_disp_intf_of_matches, -+ }, ++/* number, name, drv_data */ ++static const struct pinctrl_pin_desc aspeed_g7_soc1_pins[] = { ++ PINCTRL_PIN(C16, "C16"), ++ PINCTRL_PIN(C14, "C14"), ++ PINCTRL_PIN(C11, "C11"), ++ PINCTRL_PIN(D9, "D9"), ++ PINCTRL_PIN(F14, "F14"), ++ PINCTRL_PIN(D10, "D10"), ++ PINCTRL_PIN(C12, "C12"), ++ PINCTRL_PIN(C13, "C13"), ++ PINCTRL_PIN(AC26, "AC26"), ++ PINCTRL_PIN(AA25, "AA25"), ++ PINCTRL_PIN(AB23, "AB23"), ++ PINCTRL_PIN(U22, "U22"), ++ PINCTRL_PIN(V21, "V21"), ++ PINCTRL_PIN(N26, "N26"), ++ PINCTRL_PIN(P25, "P25"), ++ PINCTRL_PIN(N25, "N25"), ++ PINCTRL_PIN(V23, "V23"), ++ PINCTRL_PIN(W22, "W22"), ++ PINCTRL_PIN(AB26, "AB26"), ++ PINCTRL_PIN(AD26, "AD26"), ++ PINCTRL_PIN(P26, "P26"), ++ PINCTRL_PIN(AE26, "AE26"), ++ PINCTRL_PIN(AF26, "AF26"), ++ PINCTRL_PIN(AF25, "AF25"), ++ PINCTRL_PIN(AE25, "AE25"), ++ PINCTRL_PIN(AD25, "AD25"), ++ PINCTRL_PIN(AF23, "AF23"), ++ PINCTRL_PIN(AF20, "AF20"), ++ PINCTRL_PIN(AF21, "AF21"), ++ PINCTRL_PIN(AE21, "AE21"), ++ PINCTRL_PIN(AE23, "AE23"), ++ PINCTRL_PIN(AD22, "AD22"), ++ PINCTRL_PIN(AF17, "AF17"), ++ PINCTRL_PIN(AA16, "AA16"), ++ PINCTRL_PIN(Y16, "Y16"), ++ PINCTRL_PIN(V17, "V17"), ++ PINCTRL_PIN(J13, "J13"), ++ PINCTRL_PIN(AB16, "AB16"), ++ PINCTRL_PIN(AC16, "AC16"), ++ PINCTRL_PIN(AF16, "AF16"), ++ PINCTRL_PIN(AA15, "AA15"), ++ PINCTRL_PIN(AB15, "AB15"), ++ PINCTRL_PIN(AC15, "AC15"), ++ PINCTRL_PIN(AD15, "AD15"), ++ PINCTRL_PIN(Y15, "Y15"), ++ PINCTRL_PIN(AA14, "AA14"), ++ PINCTRL_PIN(W16, "W16"), ++ PINCTRL_PIN(V16, "V16"), ++ PINCTRL_PIN(AB18, "AB18"), ++ PINCTRL_PIN(AC18, "AC18"), ++ PINCTRL_PIN(K13, "K13"), ++ PINCTRL_PIN(AA17, "AA17"), ++ PINCTRL_PIN(AB17, "AB17"), ++ PINCTRL_PIN(AD16, "AD16"), ++ PINCTRL_PIN(AC17, "AC17"), ++ PINCTRL_PIN(AD17, "AD17"), ++ PINCTRL_PIN(AE16, "AE16"), ++ PINCTRL_PIN(AE17, "AE17"), ++ PINCTRL_PIN(AB24, "AB24"), ++ PINCTRL_PIN(W26, "W26"), ++ PINCTRL_PIN(HOLE0, "HOLE0"), ++ PINCTRL_PIN(HOLE1, "HOLE1"), ++ PINCTRL_PIN(HOLE2, "HOLE2"), ++ PINCTRL_PIN(HOLE3, "HOLE3"), ++ PINCTRL_PIN(W25, "W25"), ++ PINCTRL_PIN(Y23, "Y23"), ++ PINCTRL_PIN(Y24, "Y24"), ++ PINCTRL_PIN(W21, "W21"), ++ PINCTRL_PIN(AA23, "AA23"), ++ PINCTRL_PIN(AC22, "AC22"), ++ PINCTRL_PIN(AB22, "AB22"), ++ PINCTRL_PIN(Y21, "Y21"), ++ PINCTRL_PIN(AE20, "AE20"), ++ PINCTRL_PIN(AF19, "AF19"), ++ PINCTRL_PIN(Y22, "Y22"), ++ PINCTRL_PIN(AA20, "AA20"), ++ PINCTRL_PIN(AA22, "AA22"), ++ PINCTRL_PIN(AB20, "AB20"), ++ PINCTRL_PIN(AF18, "AF18"), ++ PINCTRL_PIN(AE19, "AE19"), ++ PINCTRL_PIN(AD20, "AD20"), ++ PINCTRL_PIN(AC20, "AC20"), ++ PINCTRL_PIN(AA21, "AA21"), ++ PINCTRL_PIN(AB21, "AB21"), ++ PINCTRL_PIN(AC19, "AC19"), ++ PINCTRL_PIN(AE18, "AE18"), ++ PINCTRL_PIN(AD19, "AD19"), ++ PINCTRL_PIN(AD18, "AD18"), ++ PINCTRL_PIN(U25, "U25"), ++ PINCTRL_PIN(U26, "U26"), ++ PINCTRL_PIN(Y26, "Y26"), ++ PINCTRL_PIN(AA24, "AA24"), ++ PINCTRL_PIN(R25, "R25"), ++ PINCTRL_PIN(AA26, "AA26"), ++ PINCTRL_PIN(R26, "R26"), ++ PINCTRL_PIN(Y25, "Y25"), ++ PINCTRL_PIN(B16, "B16"), ++ PINCTRL_PIN(D14, "D14"), ++ PINCTRL_PIN(B15, "B15"), ++ PINCTRL_PIN(B14, "B14"), ++ PINCTRL_PIN(C17, "C17"), ++ PINCTRL_PIN(B13, "B13"), ++ PINCTRL_PIN(E14, "E14"), ++ PINCTRL_PIN(C15, "C15"), ++ PINCTRL_PIN(D24, "D24"), ++ PINCTRL_PIN(B23, "B23"), ++ PINCTRL_PIN(B22, "B22"), ++ PINCTRL_PIN(C23, "C23"), ++ PINCTRL_PIN(B18, "B18"), ++ PINCTRL_PIN(B21, "B21"), ++ PINCTRL_PIN(M15, "M15"), ++ PINCTRL_PIN(B19, "B19"), ++ PINCTRL_PIN(B26, "B26"), ++ PINCTRL_PIN(A25, "A25"), ++ PINCTRL_PIN(A24, "A24"), ++ PINCTRL_PIN(B24, "B24"), ++ PINCTRL_PIN(E26, "E26"), ++ PINCTRL_PIN(A21, "A21"), ++ PINCTRL_PIN(A19, "A19"), ++ PINCTRL_PIN(A18, "A18"), ++ PINCTRL_PIN(D26, "D26"), ++ PINCTRL_PIN(C26, "C26"), ++ PINCTRL_PIN(A23, "A23"), ++ PINCTRL_PIN(A22, "A22"), ++ PINCTRL_PIN(B25, "B25"), ++ PINCTRL_PIN(F26, "F26"), ++ PINCTRL_PIN(A26, "A26"), ++ PINCTRL_PIN(A14, "A14"), ++ PINCTRL_PIN(E10, "E10"), ++ PINCTRL_PIN(E13, "E13"), ++ PINCTRL_PIN(D12, "D12"), ++ PINCTRL_PIN(F10, "F10"), ++ PINCTRL_PIN(E11, "E11"), ++ PINCTRL_PIN(F11, "F11"), ++ PINCTRL_PIN(F13, "F13"), ++ PINCTRL_PIN(N15, "N15"), ++ PINCTRL_PIN(C20, "C20"), ++ PINCTRL_PIN(C19, "C19"), ++ PINCTRL_PIN(A8, "A8"), ++ PINCTRL_PIN(R14, "R14"), ++ PINCTRL_PIN(A7, "A7"), ++ PINCTRL_PIN(P14, "P14"), ++ PINCTRL_PIN(D20, "D20"), ++ PINCTRL_PIN(A6, "A6"), ++ PINCTRL_PIN(B6, "B6"), ++ PINCTRL_PIN(N14, "N14"), ++ PINCTRL_PIN(B7, "B7"), ++ PINCTRL_PIN(B8, "B8"), ++ PINCTRL_PIN(B9, "B9"), ++ PINCTRL_PIN(M14, "M14"), ++ PINCTRL_PIN(J11, "J11"), ++ PINCTRL_PIN(E7, "E7"), ++ PINCTRL_PIN(D19, "D19"), ++ PINCTRL_PIN(B11, "B11"), ++ PINCTRL_PIN(D15, "D15"), ++ PINCTRL_PIN(B12, "B12"), ++ PINCTRL_PIN(B10, "B10"), ++ PINCTRL_PIN(P13, "P13"), ++ PINCTRL_PIN(C18, "C18"), ++ PINCTRL_PIN(C6, "C6"), ++ PINCTRL_PIN(C7, "C7"), ++ PINCTRL_PIN(D7, "D7"), ++ PINCTRL_PIN(N13, "N13"), ++ PINCTRL_PIN(C8, "C8"), ++ PINCTRL_PIN(C9, "C9"), ++ PINCTRL_PIN(C10, "C10"), ++ PINCTRL_PIN(M16, "M16"), ++ PINCTRL_PIN(A15, "A15"), ++ PINCTRL_PIN(G11, "G11"), ++ PINCTRL_PIN(H7, "H7"), ++ PINCTRL_PIN(H8, "H8"), ++ PINCTRL_PIN(H9, "H9"), ++ PINCTRL_PIN(H10, "H10"), ++ PINCTRL_PIN(H11, "H11"), ++ PINCTRL_PIN(J9, "J9"), ++ PINCTRL_PIN(J10, "J10"), ++ PINCTRL_PIN(E9, "E9"), ++ PINCTRL_PIN(F9, "F9"), ++ PINCTRL_PIN(F8, "F8"), ++ PINCTRL_PIN(M13, "M13"), ++ PINCTRL_PIN(F7, "F7"), ++ PINCTRL_PIN(D8, "D8"), ++ PINCTRL_PIN(E8, "E8"), ++ PINCTRL_PIN(L12, "L12"), ++ PINCTRL_PIN(F12, "F12"), ++ PINCTRL_PIN(E12, "E12"), ++ PINCTRL_PIN(J12, "J12"), ++ PINCTRL_PIN(G7, "G7"), ++ PINCTRL_PIN(G8, "G8"), ++ PINCTRL_PIN(G9, "G9"), ++ PINCTRL_PIN(G10, "G10"), ++ PINCTRL_PIN(K12, "K12"), ++ PINCTRL_PIN(W17, "W17"), ++ PINCTRL_PIN(V18, "V18"), ++ PINCTRL_PIN(W18, "W18"), ++ PINCTRL_PIN(Y17, "Y17"), ++ PINCTRL_PIN(AA18, "AA18"), ++ PINCTRL_PIN(AA13, "AA13"), ++ PINCTRL_PIN(Y18, "Y18"), ++ PINCTRL_PIN(AA12, "AA12"), ++ PINCTRL_PIN(W20, "W20"), ++ PINCTRL_PIN(V20, "V20"), ++ PINCTRL_PIN(Y11, "Y11"), ++ PINCTRL_PIN(V14, "V14"), ++ PINCTRL_PIN(V19, "V19"), ++ PINCTRL_PIN(W14, "W14"), ++ PINCTRL_PIN(Y20, "Y20"), ++ PINCTRL_PIN(AB19, "AB19"), ++ PINCTRL_PIN(U21, "U21"), ++ PINCTRL_PIN(T24, "T24"), ++ PINCTRL_PIN(V24, "V24"), ++ PINCTRL_PIN(V22, "V22"), ++ PINCTRL_PIN(T23, "T23"), ++ PINCTRL_PIN(AC25, "AC25"), ++ PINCTRL_PIN(AB25, "AB25"), ++ PINCTRL_PIN(AC24, "AC24"), ++ PINCTRL_PIN(SGMII0, "SGMII0"), ++ PINCTRL_PIN(PCIERC2_PERST, "PCIERC2_PERST"), ++ PINCTRL_PIN(PORTC_MODE, "PORTC_MODE"), ++ PINCTRL_PIN(PORTD_MODE, "PORTD_MODE"), +}; + -+module_platform_driver(aspeed_disp_intf_driver); -+ -+MODULE_DEVICE_TABLE(of, aspeed_disp_intf_of_matches); -+MODULE_AUTHOR("Jammy Huang "); -+MODULE_DESCRIPTION("ASPEED Display Interface Driver"); -+MODULE_LICENSE("GPL"); -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 2026-04-08 18:03:48.310705320 +0000 -@@ -0,0 +1,1435 @@ -+// 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 -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "aspeed-pcie-mmbi.h" -+ -+#define PCI_BMC_HOST2BMC_Q1 0x30000 -+#define PCI_BMC_HOST2BMC_Q2 0x30010 -+#define PCI_BMC_BMC2HOST_Q1 0x30020 -+#define PCI_BMC_BMC2HOST_Q2 0x30030 -+#define PCI_BMC_BMC2HOST_STS 0x30040 -+#define BMC2HOST_INT_STS_DOORBELL BIT(31) -+#define BMC2HOST_ENABLE_INTB BIT(30) -+ -+#define BMC2HOST_Q1_FULL BIT(27) -+#define BMC2HOST_Q1_EMPTY BIT(26) -+#define BMC2HOST_Q2_FULL BIT(25) -+#define BMC2HOST_Q2_EMPTY BIT(24) -+#define BMC2HOST_Q1_FULL_UNMASK BIT(23) -+#define BMC2HOST_Q1_EMPTY_UNMASK BIT(22) -+#define BMC2HOST_Q2_FULL_UNMASK BIT(21) -+#define BMC2HOST_Q2_EMPTY_UNMASK BIT(20) -+ -+#define PCI_BMC_HOST2BMC_STS 0x30044 -+#define HOST2BMC_INT_STS_DOORBELL BIT(31) -+#define HOST2BMC_ENABLE_INTB BIT(30) -+ -+#define HOST2BMC_Q1_FULL BIT(27) -+#define HOST2BMC_Q1_EMPTY BIT(26) -+#define HOST2BMC_Q2_FULL BIT(25) -+#define HOST2BMC_Q2_EMPTY BIT(24) -+#define HOST2BMC_Q1_FULL_UNMASK BIT(23) -+#define HOST2BMC_Q1_EMPTY_UNMASK BIT(22) -+#define HOST2BMC_Q2_FULL_UNMASK BIT(21) -+#define HOST2BMC_Q2_EMPTY_UNMASK BIT(20) -+ -+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, -+}; ++FUNCFG_DESCL(C16, PIN_CFG(ESPI1, SCU400, GENMASK(2, 0), 1), ++ PIN_CFG(LPC1, SCU400, GENMASK(2, 0), 2), ++ PIN_CFG(SD, SCU400, GENMASK(2, 0), 3), ++ PIN_CFG(DI2C0, SCU400, GENMASK(2, 0), 4), ++ PIN_CFG(VPI, SCU400, GENMASK(2, 0), 5)); ++FUNCFG_DESCL(C14, PIN_CFG(ESPI1, SCU400, GENMASK(6, 4), (1 << 4)), ++ PIN_CFG(LPC1, SCU400, GENMASK(6, 4), (2 << 4)), ++ PIN_CFG(SD, SCU400, GENMASK(6, 4), (3 << 4)), ++ PIN_CFG(DI2C1, SCU400, GENMASK(6, 4), (4 << 4)), ++ PIN_CFG(VPI, SCU400, GENMASK(6, 4), (5 << 4))); ++FUNCFG_DESCL(C11, PIN_CFG(ESPI1, SCU400, GENMASK(10, 8), (1 << 8)), ++ PIN_CFG(LPC1, SCU400, GENMASK(10, 8), (2 << 8)), ++ PIN_CFG(SD, SCU400, GENMASK(10, 8), (3 << 8)), ++ PIN_CFG(DI2C3, SCU400, GENMASK(10, 8), (4 << 8)), ++ PIN_CFG(VPI, SCU400, GENMASK(10, 8), (5 << 8))); ++FUNCFG_DESCL(D9, PIN_CFG(ESPI1, SCU400, GENMASK(14, 12), (1 << 12)), ++ PIN_CFG(LPC1, SCU400, GENMASK(14, 12), (2 << 12)), ++ PIN_CFG(SD, SCU400, GENMASK(14, 12), (3 << 12)), ++ PIN_CFG(DI2C0, SCU400, GENMASK(14, 12), (4 << 12)), ++ PIN_CFG(VPI, SCU400, GENMASK(14, 12), (5 << 12))); ++FUNCFG_DESCL(F14, PIN_CFG(ESPI1, SCU400, GENMASK(18, 16), (1 << 16)), ++ PIN_CFG(LPC1, SCU400, GENMASK(18, 16), (2 << 16)), ++ PIN_CFG(SD, SCU400, GENMASK(18, 16), (3 << 16)), ++ PIN_CFG(DI2C1, SCU400, GENMASK(18, 16), (4 << 16)), ++ PIN_CFG(VPI, SCU400, GENMASK(18, 16), (5 << 16))); ++FUNCFG_DESCL(D10, PIN_CFG(ESPI1, SCU400, GENMASK(22, 20), (1 << 20)), ++ PIN_CFG(LPC1, SCU400, GENMASK(22, 20), (2 << 20)), ++ PIN_CFG(SD, SCU400, GENMASK(22, 20), (3 << 20)), ++ PIN_CFG(DI2C2, SCU400, GENMASK(22, 20), (4 << 20)), ++ PIN_CFG(VPI, SCU400, GENMASK(22, 20), (5 << 20))); ++FUNCFG_DESCL(C12, PIN_CFG(ESPI1, SCU400, GENMASK(26, 24), (1 << 24)), ++ PIN_CFG(LPC1, SCU400, GENMASK(26, 24), (2 << 24)), ++ PIN_CFG(SD, SCU400, GENMASK(26, 24), (3 << 24)), ++ PIN_CFG(DI2C2, SCU400, GENMASK(26, 24), (4 << 24))); ++FUNCFG_DESCL(C13, PIN_CFG(ESPI1, SCU400, GENMASK(30, 28), (1 << 28)), ++ PIN_CFG(LPC1, SCU400, GENMASK(30, 28), (2 << 28)), ++ PIN_CFG(SD, SCU400, GENMASK(30, 28), (3 << 28)), ++ PIN_CFG(DI2C3, SCU400, GENMASK(30, 28), (4 << 28))); ++FUNCFG_DESCL(AC26, PIN_CFG(TACH0, SCU404, GENMASK(2, 0), 1), ++ PIN_CFG(THRU0, SCU404, GENMASK(2, 0), 2), ++ PIN_CFG(VPI, SCU404, GENMASK(2, 0), 3)); ++FUNCFG_DESCL(AA25, PIN_CFG(TACH1, SCU404, GENMASK(6, 4), (1 << 4)), ++ PIN_CFG(THRU0, SCU404, GENMASK(6, 4), (2 << 4)), ++ PIN_CFG(VPI, SCU404, GENMASK(6, 4), (3 << 4))); ++FUNCFG_DESCL(AB23, PIN_CFG(TACH2, SCU404, GENMASK(10, 8), (1 << 8)), ++ PIN_CFG(THRU1, SCU404, GENMASK(10, 8), (2 << 8)), ++ PIN_CFG(VPI, SCU404, GENMASK(10, 8), (3 << 8))); ++FUNCFG_DESCL(U22, PIN_CFG(TACH3, SCU404, GENMASK(14, 12), (1 << 12)), ++ PIN_CFG(THRU1, SCU404, GENMASK(14, 12), (2 << 12)), ++ PIN_CFG(VPI, SCU404, GENMASK(14, 12), (3 << 12))); ++FUNCFG_DESCL(V21, PIN_CFG(TACH4, SCU404, GENMASK(18, 16), (1 << 16)), ++ PIN_CFG(VPI, SCU404, GENMASK(18, 16), (3 << 16)), ++ PIN_CFG(NCTS5, SCU404, GENMASK(18, 16), (4 << 16))); ++FUNCFG_DESCL(N26, PIN_CFG(TACH5, SCU404, GENMASK(22, 20), (1 << 20)), ++ PIN_CFG(VPI, SCU404, GENMASK(22, 20), (3 << 20)), ++ PIN_CFG(NDCD5, SCU404, GENMASK(22, 20), (4 << 20))); ++FUNCFG_DESCL(P25, PIN_CFG(TACH6, SCU404, GENMASK(26, 24), (1 << 24)), ++ PIN_CFG(VPI, SCU404, GENMASK(26, 24), (3 << 24)), ++ PIN_CFG(NDSR5, SCU404, GENMASK(26, 24), (4 << 24))); ++FUNCFG_DESCL(N25, PIN_CFG(TACH7, SCU404, GENMASK(30, 28), (1 << 28)), ++ PIN_CFG(VPI, SCU404, GENMASK(30, 28), (3 << 28)), ++ PIN_CFG(NRI5, SCU404, GENMASK(30, 28), (4 << 28))); ++FUNCFG_DESCL(V23, PIN_CFG(TACH8, SCU408, GENMASK(2, 0), 1), ++ PIN_CFG(VPI, SCU408, GENMASK(2, 0), 3), ++ PIN_CFG(NDTR5, SCU408, GENMASK(2, 0), 4)); ++FUNCFG_DESCL(W22, PIN_CFG(TACH9, SCU408, GENMASK(6, 4), (1 << 4)), ++ PIN_CFG(VPI, SCU408, GENMASK(6, 4), (3 << 4)), ++ PIN_CFG(NRTS5, SCU408, GENMASK(6, 4), (4 << 4))); ++FUNCFG_DESCL(AB26, PIN_CFG(TACH10, SCU408, GENMASK(10, 8), (1 << 8)), ++ PIN_CFG(SALT12, SCU408, GENMASK(10, 8), (2 << 8)), ++ PIN_CFG(VPI, SCU408, GENMASK(10, 8), (3 << 8)), ++ PIN_CFG(NCTS6, SCU408, GENMASK(10, 8), (4 << 8))); ++FUNCFG_DESCL(AD26, PIN_CFG(TACH11, SCU408, GENMASK(14, 12), (1 << 12)), ++ PIN_CFG(SALT13, SCU408, GENMASK(14, 12), (2 << 12)), ++ PIN_CFG(VPI, SCU408, GENMASK(14, 12), (3 << 12)), ++ PIN_CFG(NDCD6, SCU408, GENMASK(14, 12), (4 << 12))); ++FUNCFG_DESCL(P26, PIN_CFG(TACH12, SCU408, GENMASK(18, 16), (1 << 16)), ++ PIN_CFG(SALT14, SCU408, GENMASK(18, 16), (2 << 16)), ++ PIN_CFG(VPI, SCU408, GENMASK(18, 16), (3 << 16)), ++ PIN_CFG(NDSR6, SCU408, GENMASK(18, 16), (4 << 16))); ++FUNCFG_DESCL(AE26, PIN_CFG(TACH13, SCU408, GENMASK(22, 20), (1 << 20)), ++ PIN_CFG(SALT15, SCU408, GENMASK(22, 20), (2 << 20)), ++ PIN_CFG(VPI, SCU408, GENMASK(22, 20), (3 << 20)), ++ PIN_CFG(NRI6, SCU408, GENMASK(22, 20), (4 << 20))); ++FUNCFG_DESCL(AF26, PIN_CFG(TACH14, SCU408, GENMASK(26, 24), (1 << 24)), ++ PIN_CFG(LPC0, SCU408, GENMASK(26, 24), (2 << 24)), ++ PIN_CFG(VPI, SCU408, GENMASK(26, 24), (3 << 24)), ++ PIN_CFG(NDTR6, SCU408, GENMASK(26, 24), (4 << 24))); ++FUNCFG_DESCL(AF25, PIN_CFG(TACH15, SCU408, GENMASK(30, 28), (1 << 28)), ++ PIN_CFG(LPC0, SCU408, GENMASK(30, 28), (2 << 28)), ++ PIN_CFG(VPI, SCU408, GENMASK(30, 28), (3 << 28)), ++ PIN_CFG(NRTS6, SCU408, GENMASK(30, 28), (4 << 28))); ++FUNCFG_DESCL(AE25, PIN_CFG(PWM0, SCU40C, GENMASK(2, 0), 1), ++ PIN_CFG(SIOPBON0, SCU40C, GENMASK(2, 0), 2), ++ PIN_CFG(VPI, SCU40C, GENMASK(2, 0), 3), ++ PIN_CFG(SPIM0, SCU40C, GENMASK(2, 0), 4)); ++FUNCFG_DESCL(AD25, PIN_CFG(PWM1, SCU40C, GENMASK(6, 4), (1 << 4)), ++ PIN_CFG(SIOPBIN0, SCU40C, GENMASK(6, 4), (2 << 4)), ++ PIN_CFG(VPI, SCU40C, GENMASK(6, 4), (3 << 4)), ++ PIN_CFG(SPIM0, SCU40C, GENMASK(6, 4), (4 << 4))); ++FUNCFG_DESCL(AF23, PIN_CFG(PWM2, SCU40C, GENMASK(10, 8), (1 << 8)), ++ PIN_CFG(SIOSCIN0, SCU40C, GENMASK(10, 8), (2 << 8)), ++ PIN_CFG(VPI, SCU40C, GENMASK(10, 8), (3 << 8)), ++ PIN_CFG(SPIM0, SCU40C, GENMASK(10, 8), (4 << 8))); ++FUNCFG_DESCL(AF20, PIN_CFG(PWM3, SCU40C, GENMASK(14, 12), (1 << 12)), ++ PIN_CFG(SIOS3N0, SCU40C, GENMASK(14, 12), (2 << 12)), ++ PIN_CFG(VPI, SCU40C, GENMASK(14, 12), (3 << 12)), ++ PIN_CFG(SPIM0, SCU40C, GENMASK(14, 12), (4 << 12))); ++FUNCFG_DESCL(AF21, PIN_CFG(PWM4, SCU40C, GENMASK(18, 16), (1 << 16)), ++ PIN_CFG(SIOS5N0, SCU40C, GENMASK(18, 16), (2 << 16)), ++ PIN_CFG(VPI, SCU40C, GENMASK(18, 16), (3 << 16)), ++ PIN_CFG(SPIM0, SCU40C, GENMASK(18, 16), (4 << 16))); ++FUNCFG_DESCL(AE21, PIN_CFG(PWM5, SCU40C, GENMASK(22, 20), (1 << 20)), ++ PIN_CFG(SIOPWREQN0, SCU40C, GENMASK(22, 20), (2 << 20)), ++ PIN_CFG(VPI, SCU40C, GENMASK(22, 20), (3 << 20)), ++ PIN_CFG(SPIM0, SCU40C, GENMASK(22, 20), (4 << 20))); ++FUNCFG_DESCL(AE23, PIN_CFG(PWM6, SCU40C, GENMASK(26, 24), (1 << 24)), ++ PIN_CFG(SIOONCTRLN0, SCU40C, GENMASK(26, 24), (2 << 24)), ++ PIN_CFG(SPIM0, SCU40C, GENMASK(26, 24), (4 << 24))); ++FUNCFG_DESCL(AD22, PIN_CFG(PWM7, SCU40C, GENMASK(30, 28), (1 << 28)), ++ PIN_CFG(SPIM0, SCU40C, GENMASK(30, 28), (4 << 28))); ++FUNCFG_DESCL(AF17, PIN_CFG(NCTS0, SCU410, GENMASK(2, 0), 1), ++ PIN_CFG(SIOPBON1, SCU410, GENMASK(2, 0), 2)); ++FUNCFG_DESCL(AA16, PIN_CFG(NDCD0, SCU410, GENMASK(6, 4), (1 << 4)), ++ PIN_CFG(SIOPBIN1, SCU410, GENMASK(6, 4), (2 << 4))); ++FUNCFG_DESCL(Y16, PIN_CFG(NDSR0, SCU410, GENMASK(10, 8), (1 << 8)), ++ PIN_CFG(SIOSCIN1, SCU410, GENMASK(10, 8), (2 << 8))); ++FUNCFG_DESCL(V17, PIN_CFG(NRI0, SCU410, GENMASK(14, 12), (1 << 12)), ++ PIN_CFG(SIOS3N1, SCU410, GENMASK(14, 12), (2 << 12))); ++FUNCFG_DESCL(J13, PIN_CFG(NDTR0, SCU410, GENMASK(18, 16), (1 << 16)), ++ PIN_CFG(SIOS5N1, SCU410, GENMASK(18, 16), (2 << 16))); ++FUNCFG_DESCL(AB16, PIN_CFG(NRTS0, SCU410, GENMASK(22, 20), (1 << 20)), ++ PIN_CFG(SIOPWREQN1, SCU410, GENMASK(22, 20), (2 << 20))); ++FUNCFG_DESCL(AC16, PIN_CFG(TXD0, SCU410, GENMASK(26, 24), (1 << 24))); ++FUNCFG_DESCL(AF16, PIN_CFG(RXD0, SCU410, GENMASK(30, 28), (1 << 28))); ++FUNCFG_DESCL(AA15, PIN_CFG(NCTS1, SCU414, GENMASK(2, 0), 1), ++ PIN_CFG(SIOONCTRLN1, SCU414, GENMASK(2, 0), 2)); ++FUNCFG_DESCL(AB15, PIN_CFG(NDCD1, SCU414, GENMASK(6, 4), (1 << 4)), ++ PIN_CFG(SIOPWRGD1, SCU414, GENMASK(6, 4), (2 << 4))); ++FUNCFG_DESCL(AC15, PIN_CFG(NDSR1, SCU414, GENMASK(10, 8), (1 << 8)), ++ PIN_CFG(SALT2, SCU414, GENMASK(10, 8), (2 << 8))); ++FUNCFG_DESCL(AD15, PIN_CFG(NRI1, SCU414, GENMASK(14, 12), (1 << 12)), ++ PIN_CFG(SALT3, SCU414, GENMASK(14, 12), (2 << 12))); ++FUNCFG_DESCL(Y15, PIN_CFG(NDTR1, SCU414, GENMASK(18, 16), (1 << 16))); ++FUNCFG_DESCL(AA14, PIN_CFG(NRTS1, SCU414, GENMASK(22, 20), (1 << 20))); ++FUNCFG_DESCL(W16, PIN_CFG(TXD1, SCU414, GENMASK(26, 24), (1 << 24))); ++FUNCFG_DESCL(V16, PIN_CFG(RXD1, SCU414, GENMASK(30, 28), (1 << 28))); ++FUNCFG_DESCL(AB18, PIN_CFG(TXD2, SCU418, GENMASK(2, 0), 1)); ++FUNCFG_DESCL(AC18, PIN_CFG(RXD2, SCU418, GENMASK(6, 4), (1 << 4)), ++ PIN_CFG(I2C12, SCU418, GENMASK(6, 4), (4 << 4))); ++FUNCFG_DESCL(K13, PIN_CFG(TXD3, SCU418, GENMASK(10, 8), (1 << 8)), ++ PIN_CFG(WDTRST0N, SCU418, GENMASK(10, 8), (2 << 8)), ++ PIN_CFG(PWM8, SCU418, GENMASK(10, 8), (3 << 8)), ++ PIN_CFG(SPIM1, SCU418, GENMASK(10, 8), (5 << 8))); ++FUNCFG_DESCL(AA17, PIN_CFG(RXD3, SCU418, GENMASK(14, 12), (1 << 12)), ++ PIN_CFG(WDTRST1N, SCU418, GENMASK(14, 12), (2 << 12)), ++ PIN_CFG(PWM9, SCU418, GENMASK(14, 12), (3 << 12)), ++ PIN_CFG(I2C12, SCU418, GENMASK(14, 12), (4 << 12)), ++ PIN_CFG(SPIM1, SCU418, GENMASK(14, 12), (5 << 12))); ++FUNCFG_DESCL(AB17, PIN_CFG(TXD5, SCU418, GENMASK(18, 16), (1 << 16)), ++ PIN_CFG(WDTRST2N, SCU418, GENMASK(18, 16), (2 << 16)), ++ PIN_CFG(PWM10, SCU418, GENMASK(18, 16), (3 << 16)), ++ PIN_CFG(I2C13, SCU418, GENMASK(18, 16), (4 << 16)), ++ PIN_CFG(SPIM1, SCU418, GENMASK(18, 16), (5 << 16))); ++FUNCFG_DESCL(AD16, PIN_CFG(RXD5, SCU418, GENMASK(22, 20), (1 << 20)), ++ PIN_CFG(WDTRST3N, SCU418, GENMASK(22, 20), (2 << 20)), ++ PIN_CFG(PWM11, SCU418, GENMASK(22, 20), (3 << 20)), ++ PIN_CFG(I2C13, SCU418, GENMASK(22, 20), (4 << 20)), ++ PIN_CFG(SPIM1, SCU418, GENMASK(22, 20), (5 << 20))); ++FUNCFG_DESCL(AC17, PIN_CFG(TXD6, SCU418, GENMASK(26, 24), (1 << 24)), ++ PIN_CFG(SALT0, SCU418, GENMASK(26, 24), (2 << 24)), ++ PIN_CFG(PWM12, SCU418, GENMASK(26, 24), (3 << 24)), ++ PIN_CFG(I2C14, SCU418, GENMASK(26, 24), (4 << 24)), ++ PIN_CFG(SPIM1, SCU418, GENMASK(26, 24), (5 << 24))); ++FUNCFG_DESCL(AD17, PIN_CFG(RXD6, SCU418, GENMASK(30, 28), (1 << 28)), ++ PIN_CFG(SALT1, SCU418, GENMASK(30, 28), (2 << 28)), ++ PIN_CFG(PWM13, SCU418, GENMASK(30, 28), (3 << 28)), ++ PIN_CFG(I2C14, SCU418, GENMASK(30, 28), (4 << 28)), ++ PIN_CFG(SPIM1, SCU418, GENMASK(30, 28), (5 << 28))); ++FUNCFG_DESCL(AE16, PIN_CFG(TXD7, SCU41C, GENMASK(2, 0), 1), ++ PIN_CFG(I2C15, SCU41C, GENMASK(2, 0), 2), ++ PIN_CFG(PWM14, SCU41C, GENMASK(2, 0), 3), ++ PIN_CFG(LPC1, SCU41C, GENMASK(2, 0), 4), ++ PIN_CFG(SPIM1, SCU41C, GENMASK(2, 0), 5)); ++FUNCFG_DESCL(AE17, PIN_CFG(RXD7, SCU41C, GENMASK(6, 4), (1 << 4)), ++ PIN_CFG(I2C15, SCU41C, GENMASK(6, 4), (2 << 4)), ++ PIN_CFG(PWM15, SCU41C, GENMASK(6, 4), (3 << 4)), ++ PIN_CFG(LPC1, SCU41C, GENMASK(6, 4), (4 << 4)), ++ PIN_CFG(SPIM1, SCU41C, GENMASK(6, 4), (5 << 4))); ++FUNCFG_DESCL(AB24, PIN_CFG(SGPM1, SCU41C, GENMASK(10, 8), (1 << 8)), ++ PIN_CFG(WDTRST7N, SCU41C, GENMASK(10, 8), (2 << 8)), ++ PIN_CFG(PESGWAKEN, SCU41C, GENMASK(10, 8), (3 << 8)), ++ PIN_CFG(SMON1, SCU41C, GENMASK(10, 8), (5 << 8))); ++FUNCFG_DESCL(W26, PIN_CFG(SGPM1, SCU41C, GENMASK(14, 12), (1 << 12)), ++ PIN_CFG(SMON1, SCU41C, GENMASK(14, 12), (5 << 12))); ++FUNCFG_DESCL(HOLE0); ++FUNCFG_DESCL(HOLE1); ++FUNCFG_DESCL(HOLE2); ++FUNCFG_DESCL(HOLE3); ++FUNCFG_DESCL(W25, PIN_CFG(HVI3C12, SCU420, GENMASK(2, 0), 1), ++ PIN_CFG(DI2C12, SCU420, GENMASK(2, 0), 2)); ++FUNCFG_DESCL(Y23, PIN_CFG(HVI3C12, SCU420, GENMASK(6, 4), (1 << 4)), ++ PIN_CFG(DI2C12, SCU420, GENMASK(6, 4), (2 << 4))); ++FUNCFG_DESCL(Y24, PIN_CFG(HVI3C13, SCU420, GENMASK(10, 8), (1 << 8)), ++ PIN_CFG(DI2C13, SCU420, GENMASK(10, 8), (2 << 8))); ++FUNCFG_DESCL(W21, PIN_CFG(HVI3C13, SCU420, GENMASK(14, 12), (1 << 12)), ++ PIN_CFG(DI2C13, SCU420, GENMASK(14, 12), (2 << 12))); ++FUNCFG_DESCL(AA23, PIN_CFG(HVI3C14, SCU420, GENMASK(18, 16), (1 << 16)), ++ PIN_CFG(DI2C14, SCU420, GENMASK(18, 16), (2 << 16))); ++FUNCFG_DESCL(AC22, PIN_CFG(HVI3C14, SCU420, GENMASK(22, 20), (1 << 20)), ++ PIN_CFG(DI2C14, SCU420, GENMASK(22, 20), (2 << 20))); ++FUNCFG_DESCL(AB22, PIN_CFG(HVI3C15, SCU420, GENMASK(26, 24), (1 << 24)), ++ PIN_CFG(DI2C15, SCU420, GENMASK(26, 24), (2 << 24))); ++FUNCFG_DESCL(Y21, PIN_CFG(HVI3C15, SCU420, GENMASK(30, 28), (1 << 28)), ++ PIN_CFG(DI2C15, SCU420, GENMASK(30, 28), (2 << 28))); ++FUNCFG_DESCL(AE20, PIN_CFG(I3C4, SCU424, GENMASK(2, 0), 1)); ++FUNCFG_DESCL(AF19, PIN_CFG(I3C4, SCU424, GENMASK(6, 4), (1 << 4))); ++FUNCFG_DESCL(Y22, PIN_CFG(I3C5, SCU424, GENMASK(10, 8), (1 << 8))); ++FUNCFG_DESCL(AA20, PIN_CFG(I3C5, SCU424, GENMASK(14, 12), (1 << 12))); ++FUNCFG_DESCL(AA22, PIN_CFG(I3C6, SCU424, GENMASK(18, 16), (1 << 16))); ++FUNCFG_DESCL(AB20, PIN_CFG(I3C6, SCU424, GENMASK(22, 20), (1 << 20))); ++FUNCFG_DESCL(AF18, PIN_CFG(I3C7, SCU424, GENMASK(26, 24), (1 << 24))); ++FUNCFG_DESCL(AE19, PIN_CFG(I3C7, SCU424, GENMASK(30, 28), (1 << 28))); ++FUNCFG_DESCL(AD20, PIN_CFG(I3C8, SCU428, GENMASK(2, 0), 1), ++ PIN_CFG(FSI0, SCU428, GENMASK(2, 0), 2)); ++FUNCFG_DESCL(AC20, PIN_CFG(I3C8, SCU428, GENMASK(6, 4), (1 << 4)), ++ PIN_CFG(FSI0, SCU428, GENMASK(6, 4), (2 << 4))); ++FUNCFG_DESCL(AA21, PIN_CFG(I3C9, SCU428, GENMASK(10, 8), (1 << 8)), ++ PIN_CFG(FSI1, SCU428, GENMASK(10, 8), (2 << 8))); ++FUNCFG_DESCL(AB21, PIN_CFG(I3C9, SCU428, GENMASK(14, 12), (1 << 12)), ++ PIN_CFG(FSI1, SCU428, GENMASK(14, 12), (2 << 12))); ++FUNCFG_DESCL(AC19, PIN_CFG(I3C10, SCU428, GENMASK(18, 16), (1 << 16)), ++ PIN_CFG(FSI2, SCU428, GENMASK(18, 16), (2 << 16))); ++FUNCFG_DESCL(AE18, PIN_CFG(I3C10, SCU428, GENMASK(22, 20), (1 << 20)), ++ PIN_CFG(FSI2, SCU428, GENMASK(22, 20), (2 << 20))); ++FUNCFG_DESCL(AD19, PIN_CFG(I3C11, SCU428, GENMASK(26, 24), (1 << 24)), ++ PIN_CFG(FSI3, SCU428, GENMASK(26, 24), (2 << 24))); ++FUNCFG_DESCL(AD18, PIN_CFG(I3C11, SCU428, GENMASK(30, 28), (1 << 28)), ++ PIN_CFG(FSI3, SCU428, GENMASK(30, 28), (2 << 28))); ++FUNCFG_DESCL(U25, PIN_CFG(HVI3C0, SCU42C, GENMASK(2, 0), 1), ++ PIN_CFG(DI2C8, SCU42C, GENMASK(2, 0), 2)); ++FUNCFG_DESCL(U26, PIN_CFG(HVI3C0, SCU42C, GENMASK(6, 4), (1 << 4)), ++ PIN_CFG(DI2C8, SCU42C, GENMASK(6, 4), (2 << 4))); ++FUNCFG_DESCL(Y26, PIN_CFG(HVI3C1, SCU42C, GENMASK(10, 8), (1 << 8)), ++ PIN_CFG(DI2C9, SCU42C, GENMASK(10, 8), (2 << 8))); ++FUNCFG_DESCL(AA24, PIN_CFG(HVI3C1, SCU42C, GENMASK(14, 12), (1 << 12)), ++ PIN_CFG(DI2C9, SCU42C, GENMASK(14, 12), (2 << 12))); ++FUNCFG_DESCL(R25, PIN_CFG(HVI3C2, SCU42C, GENMASK(18, 16), (1 << 16)), ++ PIN_CFG(DI2C10, SCU42C, GENMASK(18, 16), (2 << 16))); ++FUNCFG_DESCL(AA26, PIN_CFG(HVI3C2, SCU42C, GENMASK(22, 20), (1 << 20)), ++ PIN_CFG(DI2C10, SCU42C, GENMASK(22, 20), (2 << 20))); ++FUNCFG_DESCL(R26, PIN_CFG(HVI3C3, SCU42C, GENMASK(26, 24), (1 << 24)), ++ PIN_CFG(DI2C11, SCU42C, GENMASK(26, 24), (2 << 24))); ++FUNCFG_DESCL(Y25, PIN_CFG(HVI3C3, SCU42C, GENMASK(30, 28), (1 << 28)), ++ PIN_CFG(DI2C11, SCU42C, GENMASK(30, 28), (2 << 28))); ++FUNCFG_DESCL(B16, PIN_CFG(ESPI0, SCU430, GENMASK(2, 0), 1), ++ PIN_CFG(LPC0, SCU430, GENMASK(2, 0), 2)); ++FUNCFG_DESCL(D14, PIN_CFG(ESPI0, SCU430, GENMASK(6, 4), (1 << 4)), ++ PIN_CFG(LPC0, SCU430, GENMASK(6, 4), (2 << 4))); ++FUNCFG_DESCL(B15, PIN_CFG(ESPI0, SCU430, GENMASK(10, 8), (1 << 8)), ++ PIN_CFG(LPC0, SCU430, GENMASK(10, 8), (2 << 8))); ++FUNCFG_DESCL(B14, PIN_CFG(ESPI0, SCU430, GENMASK(14, 12), (1 << 12)), ++ PIN_CFG(LPC0, SCU430, GENMASK(14, 12), (2 << 12))); ++FUNCFG_DESCL(C17, PIN_CFG(ESPI0, SCU430, GENMASK(18, 16), (1 << 16)), ++ PIN_CFG(LPC0, SCU430, GENMASK(18, 16), (2 << 16)), ++ PIN_CFG(OSCCLK, SCU430, GENMASK(18, 16), (3 << 16))); ++FUNCFG_DESCL(B13, PIN_CFG(ESPI0, SCU430, GENMASK(22, 20), (1 << 20)), ++ PIN_CFG(LPC0, SCU430, GENMASK(22, 20), (2 << 20))); ++FUNCFG_DESCL(E14, PIN_CFG(ESPI0, SCU430, GENMASK(26, 24), (1 << 24)), ++ PIN_CFG(LPC0, SCU430, GENMASK(26, 24), (2 << 24))); ++FUNCFG_DESCL(C15, PIN_CFG(ESPI0, SCU430, GENMASK(30, 28), (1 << 28)), ++ PIN_CFG(LPC0, SCU430, GENMASK(30, 28), (2 << 28))); ++FUNCFG_DESCL(D24, PIN_CFG(SPI0, SCU434, GENMASK(2, 0), 1)); ++FUNCFG_DESCL(B23, PIN_CFG(SPI0, SCU434, GENMASK(6, 4), (1 << 4))); ++FUNCFG_DESCL(B22, PIN_CFG(SPI0, SCU434, GENMASK(10, 8), (1 << 8))); ++FUNCFG_DESCL(C23, PIN_CFG(QSPI0, SCU434, GENMASK(14, 12), (1 << 12))); ++FUNCFG_DESCL(B18, PIN_CFG(QSPI0, SCU434, GENMASK(18, 16), (1 << 16))); ++FUNCFG_DESCL(B21, PIN_CFG(SPI0CS1, SCU434, GENMASK(22, 20), (1 << 20))); ++FUNCFG_DESCL(M15, PIN_CFG(SPI0ABR, SCU434, GENMASK(26, 24), (1 << 24)), ++ PIN_CFG(TXD8, SCU434, GENMASK(26, 24), (3 << 24))); ++FUNCFG_DESCL(B19, PIN_CFG(SPI0WPN, SCU434, GENMASK(30, 28), (1 << 28)), ++ PIN_CFG(RXD8, SCU434, GENMASK(30, 28), (3 << 28))); ++FUNCFG_DESCL(B26, PIN_CFG(SPI1, SCU438, GENMASK(2, 0), 1), ++ PIN_CFG(TXD9, SCU438, GENMASK(2, 0), 3)); ++FUNCFG_DESCL(A25, PIN_CFG(SPI1, SCU438, GENMASK(6, 4), (1 << 4)), ++ PIN_CFG(RXD9, SCU438, GENMASK(6, 4), (3 << 4))); ++FUNCFG_DESCL(A24, PIN_CFG(SPI1, SCU438, GENMASK(10, 8), (1 << 8)), ++ PIN_CFG(TXD10, SCU438, GENMASK(10, 8), (3 << 8))); ++FUNCFG_DESCL(B24, PIN_CFG(QSPI1, SCU438, GENMASK(14, 12), (1 << 12)), ++ PIN_CFG(RXD10, SCU438, GENMASK(14, 12), (3 << 12))); ++FUNCFG_DESCL(E26, PIN_CFG(QSPI1, SCU438, GENMASK(18, 16), (1 << 16)), ++ PIN_CFG(TXD11, SCU438, GENMASK(18, 16), (3 << 16))); ++FUNCFG_DESCL(A21, PIN_CFG(SPI1CS1, SCU438, GENMASK(22, 20), (1 << 20)), ++ PIN_CFG(RXD11, SCU438, GENMASK(22, 20), (3 << 20))); ++FUNCFG_DESCL(A19, PIN_CFG(SPI1ABR, SCU438, GENMASK(26, 24), (1 << 24)), ++ PIN_CFG(THRU2, SCU438, GENMASK(26, 24), (4 << 24))); ++FUNCFG_DESCL(A18, PIN_CFG(SPI1WPN, SCU438, GENMASK(30, 28), (1 << 28)), ++ PIN_CFG(THRU2, SCU438, GENMASK(30, 28), (4 << 28))); ++FUNCFG_DESCL(D26, PIN_CFG(SPI2, SCU43C, GENMASK(2, 0), 1)); ++FUNCFG_DESCL(C26, PIN_CFG(SPI2, SCU43C, GENMASK(6, 4), (1 << 4))); ++FUNCFG_DESCL(A23, PIN_CFG(SPI2, SCU43C, GENMASK(10, 8), (1 << 8))); ++FUNCFG_DESCL(A22, PIN_CFG(SPI2, SCU43C, GENMASK(14, 12), (1 << 12))); ++FUNCFG_DESCL(B25, PIN_CFG(QSPI2, SCU43C, GENMASK(18, 16), (1 << 16)), ++ PIN_CFG(THRU3, SCU43C, GENMASK(18, 16), (4 << 16))); ++FUNCFG_DESCL(F26, PIN_CFG(QSPI2, SCU43C, GENMASK(22, 20), (1 << 20)), ++ PIN_CFG(THRU3, SCU43C, GENMASK(22, 20), (4 << 20))); ++FUNCFG_DESCL(A26, PIN_CFG(SPI2CS1, SCU43C, GENMASK(26, 24), (1 << 24))); ++FUNCFG_DESCL(A14, PIN_CFG(FWSPIABR, SCU43C, GENMASK(30, 28), (1 << 28))); ++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(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))); ++FUNCFG_DESCL(F13, PIN_CFG(JTAGM1, SCU440, GENMASK(26, 24), (1 << 24))); ++FUNCFG_DESCL(N15, PIN_CFG(FWSPIWPEN, SCU440, GENMASK(30, 28), (1 << 28))); ++FUNCFG_DESCL(C20, PIN_CFG(RGMII0, SCU444, GENMASK(2, 0), 1), ++ PIN_CFG(RMII0, SCU444, GENMASK(2, 0), 2)); ++FUNCFG_DESCL(C19, PIN_CFG(RGMII0, SCU444, GENMASK(6, 4), (1 << 4))); ++FUNCFG_DESCL(A8, PIN_CFG(RGMII0, SCU444, GENMASK(10, 8), (1 << 8)), ++ PIN_CFG(RMII0, SCU444, GENMASK(10, 8), (2 << 8))); ++FUNCFG_DESCL(R14, PIN_CFG(RGMII0, SCU444, GENMASK(14, 12), (1 << 12)), ++ PIN_CFG(RMII0, SCU444, GENMASK(14, 12), (2 << 12))); ++FUNCFG_DESCL(A7, PIN_CFG(RGMII0, SCU444, GENMASK(18, 16), (1 << 16)), ++ PIN_CFG(RMII0, SCU444, GENMASK(18, 16), (2 << 16))); ++FUNCFG_DESCL(P14, PIN_CFG(RGMII0, SCU444, GENMASK(22, 20), (1 << 20)), ++ PIN_CFG(RMII0, SCU444, GENMASK(22, 20), (2 << 20))); ++FUNCFG_DESCL(D20, PIN_CFG(RGMII0, SCU444, GENMASK(26, 24), (1 << 24)), ++ PIN_CFG(RMII0RCLKO, SCU444, GENMASK(26, 24), (2 << 24))); ++FUNCFG_DESCL(A6, PIN_CFG(RGMII0, SCU444, GENMASK(30, 28), (1 << 28)), ++ PIN_CFG(RMII0, SCU444, GENMASK(30, 28), (2 << 28))); ++FUNCFG_DESCL(B6, PIN_CFG(RGMII0, SCU448, GENMASK(2, 0), 1), ++ PIN_CFG(RMII0, SCU448, GENMASK(2, 0), 2)); ++FUNCFG_DESCL(N14, PIN_CFG(RGMII0, SCU448, GENMASK(6, 4), (1 << 4)), ++ PIN_CFG(RMII0, SCU448, GENMASK(6, 4), (2 << 4))); ++FUNCFG_DESCL(B7, PIN_CFG(RGMII0, SCU448, GENMASK(10, 8), (1 << 8))); ++FUNCFG_DESCL(B8, PIN_CFG(RGMII0, SCU448, GENMASK(14, 12), (1 << 12))); ++FUNCFG_DESCL(B9, PIN_CFG(MDIO0, SCU448, GENMASK(18, 16), (1 << 16))); ++FUNCFG_DESCL(M14, PIN_CFG(MDIO0, SCU448, GENMASK(22, 20), (1 << 20))); ++FUNCFG_DESCL(J11, PIN_CFG(VGA, SCU448, GENMASK(26, 24), (1 << 24))); ++FUNCFG_DESCL(E7, PIN_CFG(VGA, SCU448, GENMASK(30, 28), (1 << 28))); ++FUNCFG_DESCL(D19, PIN_CFG(RGMII1, SCU44C, GENMASK(2, 0), 1), ++ PIN_CFG(RMII1, SCU44C, GENMASK(2, 0), 2), ++ PIN_CFG(DSGPM0, SCU44C, GENMASK(2, 0), 4)); ++FUNCFG_DESCL(B11, PIN_CFG(RGMII1, SCU44C, GENMASK(6, 4), (1 << 4)), ++ PIN_CFG(SGPS, SCU44C, GENMASK(6, 4), (5 << 4))); ++FUNCFG_DESCL(D15, PIN_CFG(RGMII1, SCU44C, GENMASK(10, 8), (1 << 8)), ++ PIN_CFG(RMII1, SCU44C, GENMASK(10, 8), (2 << 8)), ++ PIN_CFG(TXD3, SCU44C, GENMASK(10, 8), (4 << 8))); ++FUNCFG_DESCL(B12, PIN_CFG(RGMII1, SCU44C, GENMASK(14, 12), (1 << 12)), ++ PIN_CFG(RMII1, SCU44C, GENMASK(14, 12), (2 << 12)), ++ PIN_CFG(RXD3, SCU44C, GENMASK(14, 12), (4 << 12))); ++FUNCFG_DESCL(B10, PIN_CFG(RGMII1, SCU44C, GENMASK(18, 16), (1 << 16)), ++ PIN_CFG(RMII1, SCU44C, GENMASK(18, 16), (2 << 16)), ++ PIN_CFG(DSGPM0, SCU44C, GENMASK(18, 16), (4 << 16))); ++FUNCFG_DESCL(P13, PIN_CFG(RGMII1, SCU44C, GENMASK(22, 20), (1 << 20)), ++ PIN_CFG(RMII1, SCU44C, GENMASK(22, 20), (2 << 20))); ++FUNCFG_DESCL(C18, PIN_CFG(RGMII1, SCU44C, GENMASK(26, 24), (1 << 24)), ++ PIN_CFG(RMII1RCLKO, SCU44C, GENMASK(26, 24), (2 << 24)), ++ PIN_CFG(SGPS, SCU44C, GENMASK(26, 24), (5 << 24))); ++FUNCFG_DESCL(C6, PIN_CFG(RGMII1, SCU44C, GENMASK(30, 28), (1 << 28)), ++ PIN_CFG(RMII1, SCU44C, GENMASK(30, 28), (2 << 28))); ++FUNCFG_DESCL(C7, PIN_CFG(RGMII1, SCU450, GENMASK(2, 0), 1), ++ PIN_CFG(RMII1, SCU450, GENMASK(2, 0), 2), ++ PIN_CFG(DSGPM0, SCU450, GENMASK(2, 0), 4)); ++FUNCFG_DESCL(D7, PIN_CFG(RGMII1, SCU450, GENMASK(6, 4), (1 << 4)), ++ PIN_CFG(RMII1, SCU450, GENMASK(6, 4), (2 << 4)), ++ PIN_CFG(DSGPM0, SCU450, GENMASK(6, 4), (4 << 4))); ++FUNCFG_DESCL(N13, PIN_CFG(RGMII1, SCU450, GENMASK(10, 8), (1 << 8)), ++ PIN_CFG(SGPS, SCU450, GENMASK(10, 8), (5 << 8))); ++FUNCFG_DESCL(C8, PIN_CFG(RGMII1, SCU450, GENMASK(14, 12), (1 << 12)), ++ PIN_CFG(SGPS, SCU450, GENMASK(14, 12), (5 << 12))); ++FUNCFG_DESCL(C9, PIN_CFG(MDIO1, SCU450, GENMASK(18, 16), (1 << 16))); ++FUNCFG_DESCL(C10, PIN_CFG(MDIO1, SCU450, GENMASK(22, 20), (1 << 20))); ++FUNCFG_DESCL(M16, PIN_CFG(FWQSPI, SCU450, GENMASK(26, 24), (1 << 24))); ++FUNCFG_DESCL(A15, PIN_CFG(FWQSPI, SCU450, GENMASK(30, 28), (1 << 28))); ++FUNCFG_DESCL(G11, PIN_CFG(I2C0, SCU454, GENMASK(2, 0), 1), ++ PIN_CFG(LTPI_PS_I2C0, SCU454, GENMASK(2, 0), 2)); ++FUNCFG_DESCL(H7, PIN_CFG(I2C0, SCU454, GENMASK(6, 4), (1 << 4)), ++ PIN_CFG(LTPI_PS_I2C0, SCU454, GENMASK(6, 4), (2 << 4))); ++FUNCFG_DESCL(H8, PIN_CFG(I2C1, SCU454, GENMASK(10, 8), (1 << 8)), ++ PIN_CFG(LTPI_PS_I2C1, SCU454, GENMASK(10, 8), (2 << 8))); ++FUNCFG_DESCL(H9, PIN_CFG(I2C1, SCU454, GENMASK(14, 12), (1 << 12)), ++ PIN_CFG(LTPI_PS_I2C1, SCU454, GENMASK(14, 12), (2 << 12))); ++FUNCFG_DESCL(H10, PIN_CFG(I2C2, SCU454, GENMASK(18, 16), (1 << 16)), ++ PIN_CFG(LTPI_PS_I2C2, SCU454, GENMASK(18, 16), (2 << 16))); ++FUNCFG_DESCL(H11, PIN_CFG(I2C2, SCU454, GENMASK(22, 20), (1 << 20)), ++ PIN_CFG(LTPI_PS_I2C2, SCU454, GENMASK(22, 20), (2 << 20))); ++FUNCFG_DESCL(J9, PIN_CFG(I2C3, SCU454, GENMASK(26, 24), (1 << 24)), ++ PIN_CFG(LTPI_PS_I2C3, SCU454, GENMASK(26, 24), (2 << 24))); ++FUNCFG_DESCL(J10, PIN_CFG(I2C3, SCU454, GENMASK(30, 28), (1 << 28)), ++ PIN_CFG(LTPI_PS_I2C3, SCU454, GENMASK(30, 28), (2 << 28))); ++FUNCFG_DESCL(E9, PIN_CFG(I2C4, SCU458, GENMASK(2, 0), 1), ++ PIN_CFG(I2CF1, SCU458, GENMASK(2, 0), 5)); ++FUNCFG_DESCL(F9, PIN_CFG(I2C4, SCU458, GENMASK(6, 4), (1 << 4)), ++ PIN_CFG(I2CF1, SCU458, GENMASK(6, 4), (5 << 4))); ++FUNCFG_DESCL(F8, PIN_CFG(I2C5, SCU458, GENMASK(10, 8), (1 << 8)), ++ PIN_CFG(I2CF1, SCU458, GENMASK(10, 8), (5 << 8))); ++FUNCFG_DESCL(M13, PIN_CFG(I2C5, SCU458, GENMASK(14, 12), (1 << 12)), ++ PIN_CFG(I2CF1, SCU458, GENMASK(14, 12), (5 << 12))); ++FUNCFG_DESCL(F7, PIN_CFG(I2C6, SCU458, GENMASK(18, 16), (1 << 16)), ++ PIN_CFG(I2CF2, SCU458, GENMASK(18, 16), (5 << 16))); ++FUNCFG_DESCL(D8, PIN_CFG(I2C6, SCU458, GENMASK(22, 20), (1 << 20)), ++ PIN_CFG(I2CF2, SCU458, GENMASK(22, 20), (5 << 20))); ++FUNCFG_DESCL(E8, PIN_CFG(I2C7, SCU458, GENMASK(26, 24), (1 << 24)), ++ PIN_CFG(I2CF2, SCU458, GENMASK(26, 24), (5 << 24))); ++FUNCFG_DESCL(L12, PIN_CFG(I2C7, SCU458, GENMASK(30, 28), (1 << 28)), ++ PIN_CFG(I2CF2, SCU458, GENMASK(30, 28), (5 << 28))); ++FUNCFG_DESCL(F12, PIN_CFG(I2C8, SCU45C, GENMASK(2, 0), 1), ++ PIN_CFG(I2CF0, SCU45C, GENMASK(2, 0), 5)); ++FUNCFG_DESCL(E12, PIN_CFG(I2C8, SCU45C, GENMASK(6, 4), (1 << 4)), ++ PIN_CFG(I2CF0, SCU45C, GENMASK(6, 4), (5 << 4))); ++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(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))); ++FUNCFG_DESCL(G9, PIN_CFG(I2C10, SCU45C, GENMASK(22, 20), (1 << 20)), ++ PIN_CFG(CANBUS, SCU45C, GENMASK(22, 20), (2 << 20))); ++FUNCFG_DESCL(G10, PIN_CFG(I2C11, SCU45C, GENMASK(26, 24), (1 << 24)), ++ PIN_CFG(USBUART, SCU45C, GENMASK(26, 24), (2 << 24))); ++FUNCFG_DESCL(K12, PIN_CFG(I2C11, SCU45C, GENMASK(30, 28), (1 << 28)), ++ PIN_CFG(USBUART, SCU45C, GENMASK(30, 28), (2 << 28))); ++FUNCFG_DESCL(W17, PIN_CFG(ADC0, SCU460, GENMASK(2, 0), 0), ++ PIN_CFG(GPIY0, SCU460, GENMASK(2, 0), 1), ++ PIN_CFG(SALT4, SCU460, GENMASK(2, 0), 2)); ++FUNCFG_DESCL(V18, PIN_CFG(ADC1, SCU460, GENMASK(6, 4), 0), ++ PIN_CFG(GPIY1, SCU460, GENMASK(6, 4), (1 << 4)), ++ PIN_CFG(SALT5, SCU460, GENMASK(6, 4), (2 << 4))); ++FUNCFG_DESCL(W18, PIN_CFG(ADC2, SCU460, GENMASK(10, 8), 0), ++ PIN_CFG(GPIY2, SCU460, GENMASK(10, 8), (1 << 8)), ++ PIN_CFG(SALT6, SCU460, GENMASK(10, 8), (2 << 8))); ++FUNCFG_DESCL(Y17, PIN_CFG(ADC3, SCU460, GENMASK(14, 12), 0), ++ PIN_CFG(GPIY3, SCU460, GENMASK(14, 12), (1 << 12)), ++ PIN_CFG(SALT7, SCU460, GENMASK(14, 12), (2 << 12))); ++FUNCFG_DESCL(AA18, PIN_CFG(ADC4, SCU460, GENMASK(18, 16), 0), ++ PIN_CFG(GPIY4, SCU460, GENMASK(18, 16), (1 << 16)), ++ PIN_CFG(SALT8, SCU460, GENMASK(18, 16), (2 << 16))); ++FUNCFG_DESCL(AA13, PIN_CFG(ADC5, SCU460, GENMASK(22, 20), 0), ++ PIN_CFG(GPIY5, SCU460, GENMASK(22, 20), (1 << 20)), ++ PIN_CFG(SALT9, SCU460, GENMASK(22, 20), (2 << 20))); ++FUNCFG_DESCL(Y18, PIN_CFG(ADC6, SCU460, GENMASK(26, 24), 0), ++ PIN_CFG(GPIY6, SCU460, GENMASK(26, 24), (1 << 24)), ++ PIN_CFG(SALT10, SCU460, GENMASK(26, 24), (2 << 24))); ++FUNCFG_DESCL(AA12, PIN_CFG(ADC7, SCU460, GENMASK(30, 28), 0), ++ PIN_CFG(GPIY7, SCU460, GENMASK(30, 28), (1 << 28)), ++ PIN_CFG(SALT11, SCU460, GENMASK(30, 28), (2 << 28))); ++FUNCFG_DESCL(W20, PIN_CFG(ADC8, SCU464, GENMASK(2, 0), 0), ++ PIN_CFG(GPIZ0, SCU464, GENMASK(2, 0), 1)); ++FUNCFG_DESCL(V20, PIN_CFG(ADC9, SCU464, GENMASK(6, 4), 0), ++ PIN_CFG(GPIZ1, SCU464, GENMASK(6, 4), (1 << 4))); ++FUNCFG_DESCL(Y11, PIN_CFG(ADC10, SCU464, GENMASK(10, 8), 0), ++ PIN_CFG(GPIZ2, SCU464, GENMASK(10, 8), (1 << 8))); ++FUNCFG_DESCL(V14, PIN_CFG(ADC11, SCU464, GENMASK(14, 12), 0), ++ PIN_CFG(GPIZ3, SCU464, GENMASK(14, 12), (1 << 12))); ++FUNCFG_DESCL(V19, PIN_CFG(ADC12, SCU464, GENMASK(18, 16), 0), ++ PIN_CFG(GPIZ4, SCU464, GENMASK(18, 16), (1 << 16))); ++FUNCFG_DESCL(W14, PIN_CFG(ADC13, SCU464, GENMASK(22, 20), 0), ++ PIN_CFG(GPIZ5, SCU464, GENMASK(22, 20), (1 << 20)), ++ PIN_CFG(AUXPWRGOOD0, SCU464, GENMASK(22, 20), (2 << 20))); ++FUNCFG_DESCL(Y20, PIN_CFG(ADC14, SCU464, GENMASK(26, 24), 0), ++ PIN_CFG(GPIZ6, SCU464, GENMASK(26, 24), (1 << 24)), ++ PIN_CFG(AUXPWRGOOD1, SCU464, GENMASK(26, 24), (2 << 24))); ++FUNCFG_DESCL(AB19, PIN_CFG(ADC15, SCU464, GENMASK(30, 28), 0), ++ PIN_CFG(GPIZ7, SCU464, GENMASK(30, 28), (1 << 28))); ++FUNCFG_DESCL(U21, PIN_CFG(SGPM0, SCU468, GENMASK(2, 0), 1), ++ PIN_CFG(SMON0, SCU468, GENMASK(2, 0), 2), ++ PIN_CFG(NCTS2, SCU468, GENMASK(2, 0), 3), ++ PIN_CFG(MACLINK0, SCU468, GENMASK(2, 0), 4)); ++FUNCFG_DESCL(T24, PIN_CFG(SGPM0, SCU468, GENMASK(6, 4), (1 << 4)), ++ PIN_CFG(SMON0, SCU468, GENMASK(6, 4), (2 << 4)), ++ PIN_CFG(NDCD2, SCU468, GENMASK(6, 4), (3 << 4)), ++ PIN_CFG(MACLINK2, SCU468, GENMASK(6, 4), (4 << 4))); ++FUNCFG_DESCL(V24, PIN_CFG(SGPM0LD_R, SCU468, GENMASK(10, 8), (2 << 8)), ++ PIN_CFG(HBLED, SCU468, GENMASK(10, 8), (2 << 8))); ++FUNCFG_DESCL(V22, PIN_CFG(SGPM0, SCU468, GENMASK(14, 12), (1 << 12)), ++ PIN_CFG(SMON0, SCU468, GENMASK(14, 12), (2 << 12)), ++ PIN_CFG(NDSR2, SCU468, GENMASK(14, 12), (3 << 12))); ++FUNCFG_DESCL(T23, PIN_CFG(SGPM0, SCU468, GENMASK(18, 16), (1 << 16)), ++ PIN_CFG(SMON0, SCU468, GENMASK(18, 16), (2 << 16)), ++ PIN_CFG(NRI2, SCU468, GENMASK(18, 16), (3 << 16))); ++FUNCFG_DESCL(AC25, PIN_CFG(SGPM1, SCU468, GENMASK(22, 20), (1 << 20)), ++ PIN_CFG(WDTRST4N, SCU468, GENMASK(22, 20), (2 << 20)), ++ PIN_CFG(NDTR2, SCU468, GENMASK(22, 20), (3 << 20)), ++ PIN_CFG(SMON1, SCU468, GENMASK(22, 20), (4 << 20))); ++FUNCFG_DESCL(AB25, PIN_CFG(SGPM1, SCU468, GENMASK(26, 24), (1 << 24)), ++ PIN_CFG(WDTRST5N, SCU468, GENMASK(26, 24), (2 << 24)), ++ PIN_CFG(NRTS2, SCU468, GENMASK(26, 24), (3 << 24)), ++ PIN_CFG(SMON1, SCU468, GENMASK(26, 24), (4 << 24))); ++FUNCFG_DESCL(AC24, PIN_CFG(SGPM1LD_R, SCU468, GENMASK(30, 28), (1 << 28)), ++ PIN_CFG(WDTRST6N, SCU468, GENMASK(30, 28), (2 << 28)), ++ PIN_CFG(MACLINK1, SCU468, GENMASK(30, 28), (3 << 28))); ++FUNCFG_DESCL(SGMII0, PIN_CFG(SGMII, SCU47C, BIT(0), 1 << 0)); ++FUNCFG_DESCL(PCIERC2_PERST, PIN_CFG(PE2SGRSTN, SCU908, BIT(1), 1 << 1)); ++FUNCFG_DESCL(PORTC_MODE, PIN_CFG(USB2CUD, SCU3B0, GENMASK(1, 0), 0), ++ PIN_CFG(USB2CD, SCU3B0, GENMASK(1, 0), 1 << 0), ++ PIN_CFG(USB2CH, SCU3B0, GENMASK(1, 0), 2 << 0), ++ PIN_CFG(USB2CU, SCU3B0, GENMASK(1, 0), 3 << 0)); ++FUNCFG_DESCL(PORTD_MODE, PIN_CFG(USB2DD, SCU3B0, GENMASK(3, 2), 1 << 2), ++ PIN_CFG(USB2DH, SCU3B0, GENMASK(3, 2), 2 << 2)); + -+enum queue_index { -+ QUEUE1 = 0, -+ QUEUE2, ++static const struct aspeed_g7_pincfg pin_cfg[] = { ++ PINCFG_PIN(C16), PINCFG_PIN(C14), PINCFG_PIN(C11), ++ PINCFG_PIN(D9), PINCFG_PIN(F14), PINCFG_PIN(D10), ++ PINCFG_PIN(C12), PINCFG_PIN(C13), PINCFG_PIN(AC26), ++ PINCFG_PIN(AA25), PINCFG_PIN(AB23), PINCFG_PIN(U22), ++ PINCFG_PIN(V21), PINCFG_PIN(N26), PINCFG_PIN(P25), ++ PINCFG_PIN(N25), PINCFG_PIN(V23), PINCFG_PIN(W22), ++ PINCFG_PIN(AB26), PINCFG_PIN(AD26), PINCFG_PIN(P26), ++ PINCFG_PIN(AE26), PINCFG_PIN(AF26), PINCFG_PIN(AF25), ++ PINCFG_PIN(AE25), PINCFG_PIN(AD25), PINCFG_PIN(AF23), ++ PINCFG_PIN(AF20), PINCFG_PIN(AF21), PINCFG_PIN(AE21), ++ PINCFG_PIN(AE23), PINCFG_PIN(AD22), PINCFG_PIN(AF17), ++ PINCFG_PIN(AA16), PINCFG_PIN(Y16), PINCFG_PIN(V17), ++ PINCFG_PIN(J13), PINCFG_PIN(AB16), PINCFG_PIN(AC16), ++ PINCFG_PIN(AF16), PINCFG_PIN(AA15), PINCFG_PIN(AB15), ++ PINCFG_PIN(AC15), PINCFG_PIN(AD15), PINCFG_PIN(Y15), ++ PINCFG_PIN(AA14), PINCFG_PIN(W16), PINCFG_PIN(V16), ++ PINCFG_PIN(AB18), PINCFG_PIN(AC18), PINCFG_PIN(K13), ++ PINCFG_PIN(AA17), PINCFG_PIN(AB17), PINCFG_PIN(AD16), ++ PINCFG_PIN(AC17), PINCFG_PIN(AD17), PINCFG_PIN(AE16), ++ PINCFG_PIN(AE17), PINCFG_PIN(AB24), PINCFG_PIN(W26), ++ PINCFG_PIN(HOLE0), PINCFG_PIN(HOLE1), PINCFG_PIN(HOLE2), ++ PINCFG_PIN(HOLE3), PINCFG_PIN(W25), PINCFG_PIN(Y23), ++ PINCFG_PIN(Y24), PINCFG_PIN(W21), PINCFG_PIN(AA23), ++ PINCFG_PIN(AC22), PINCFG_PIN(AB22), PINCFG_PIN(Y21), ++ PINCFG_PIN(AE20), PINCFG_PIN(AF19), PINCFG_PIN(Y22), ++ PINCFG_PIN(AA20), PINCFG_PIN(AA22), PINCFG_PIN(AB20), ++ PINCFG_PIN(AF18), PINCFG_PIN(AE19), PINCFG_PIN(AD20), ++ PINCFG_PIN(AC20), PINCFG_PIN(AA21), PINCFG_PIN(AB21), ++ PINCFG_PIN(AC19), PINCFG_PIN(AE18), PINCFG_PIN(AD19), ++ PINCFG_PIN(AD18), PINCFG_PIN(U25), PINCFG_PIN(U26), ++ PINCFG_PIN(Y26), PINCFG_PIN(AA24), PINCFG_PIN(R25), ++ PINCFG_PIN(AA26), PINCFG_PIN(R26), PINCFG_PIN(Y25), ++ PINCFG_PIN(B16), PINCFG_PIN(D14), PINCFG_PIN(B15), ++ PINCFG_PIN(B14), PINCFG_PIN(C17), PINCFG_PIN(B13), ++ PINCFG_PIN(E14), PINCFG_PIN(C15), PINCFG_PIN(D24), ++ PINCFG_PIN(B23), PINCFG_PIN(B22), PINCFG_PIN(C23), ++ PINCFG_PIN(B18), PINCFG_PIN(B21), PINCFG_PIN(M15), ++ PINCFG_PIN(B19), PINCFG_PIN(B26), PINCFG_PIN(A25), ++ PINCFG_PIN(A24), PINCFG_PIN(B24), PINCFG_PIN(E26), ++ PINCFG_PIN(A21), PINCFG_PIN(A19), PINCFG_PIN(A18), ++ PINCFG_PIN(D26), PINCFG_PIN(C26), PINCFG_PIN(A23), ++ PINCFG_PIN(A22), PINCFG_PIN(B25), PINCFG_PIN(F26), ++ PINCFG_PIN(A26), PINCFG_PIN(A14), PINCFG_PIN(E10), ++ PINCFG_PIN(E13), PINCFG_PIN(D12), PINCFG_PIN(F10), ++ PINCFG_PIN(E11), PINCFG_PIN(F11), PINCFG_PIN(F13), ++ PINCFG_PIN(N15), PINCFG_PIN(C20), PINCFG_PIN(C19), ++ PINCFG_PIN(A8), PINCFG_PIN(R14), PINCFG_PIN(A7), ++ PINCFG_PIN(P14), PINCFG_PIN(D20), PINCFG_PIN(A6), ++ PINCFG_PIN(B6), PINCFG_PIN(N14), PINCFG_PIN(B7), ++ PINCFG_PIN(B8), PINCFG_PIN(B9), PINCFG_PIN(M14), ++ PINCFG_PIN(J11), PINCFG_PIN(E7), PINCFG_PIN(D19), ++ PINCFG_PIN(B11), PINCFG_PIN(D15), PINCFG_PIN(B12), ++ PINCFG_PIN(B10), PINCFG_PIN(P13), PINCFG_PIN(C18), ++ PINCFG_PIN(C6), PINCFG_PIN(C7), PINCFG_PIN(D7), ++ PINCFG_PIN(N13), PINCFG_PIN(C8), PINCFG_PIN(C9), ++ PINCFG_PIN(C10), PINCFG_PIN(M16), PINCFG_PIN(A15), ++ PINCFG_PIN(G11), PINCFG_PIN(H7), PINCFG_PIN(H8), ++ PINCFG_PIN(H9), PINCFG_PIN(H10), PINCFG_PIN(H11), ++ PINCFG_PIN(J9), PINCFG_PIN(J10), PINCFG_PIN(E9), ++ PINCFG_PIN(F9), PINCFG_PIN(F8), PINCFG_PIN(M13), ++ PINCFG_PIN(F7), PINCFG_PIN(D8), PINCFG_PIN(E8), ++ PINCFG_PIN(L12), PINCFG_PIN(F12), PINCFG_PIN(E12), ++ PINCFG_PIN(J12), PINCFG_PIN(G7), PINCFG_PIN(G8), ++ PINCFG_PIN(G9), PINCFG_PIN(G10), PINCFG_PIN(K12), ++ PINCFG_PIN(W17), PINCFG_PIN(V18), PINCFG_PIN(W18), ++ PINCFG_PIN(Y17), PINCFG_PIN(AA18), PINCFG_PIN(AA13), ++ PINCFG_PIN(Y18), PINCFG_PIN(AA12), PINCFG_PIN(W20), ++ PINCFG_PIN(V20), PINCFG_PIN(Y11), PINCFG_PIN(V14), ++ PINCFG_PIN(V19), PINCFG_PIN(W14), PINCFG_PIN(Y20), ++ PINCFG_PIN(AB19), PINCFG_PIN(U21), PINCFG_PIN(T24), ++ PINCFG_PIN(V24), PINCFG_PIN(V22), PINCFG_PIN(T23), ++ PINCFG_PIN(AC25), PINCFG_PIN(AB25), PINCFG_PIN(AC24), ++ PINCFG_PIN(SGMII0), PINCFG_PIN(PCIERC2_PERST), ++ PINCFG_PIN(PORTC_MODE), PINCFG_PIN(PORTD_MODE), +}; + -+enum msi_index { -+ BMC_MSI, -+ MBX_MSI, -+ VUART0_MSI, -+ VUART1_MSI, -+ MMBI0_MSI, -+ MMBI1_MSI, -+ MMBI2_MSI, -+ MMBI3_MSI, -+}; ++static int aspeed_g7_soc1_dt_node_to_map(struct pinctrl_dev *pctldev, ++ struct device_node *np_config, ++ struct pinctrl_map **map, u32 *num_maps) ++{ ++ return pinconf_generic_dt_node_to_map(pctldev, np_config, map, num_maps, ++ PIN_MAP_TYPE_INVALID); ++} + -+/* 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 void aspeed_g7_soc1_dt_free_map(struct pinctrl_dev *pctldev, ++ struct pinctrl_map *map, u32 num_maps) ++{ ++ kfree(map); ++} + -+struct aspeed_platform { -+ int (*setup)(struct pci_dev *pdev); ++static const struct pinctrl_ops aspeed_g7_soc1_pinctrl_ops = { ++ .get_groups_count = aspeed_pinctrl_get_groups_count, ++ .get_group_name = aspeed_pinctrl_get_group_name, ++ .get_group_pins = aspeed_pinctrl_get_group_pins, ++ .pin_dbg_show = aspeed_pinctrl_pin_dbg_show, ++ .dt_node_to_map = aspeed_g7_soc1_dt_node_to_map, ++ .dt_free_map = aspeed_g7_soc1_dt_free_map, +}; + -+struct aspeed_queue_message { -+ /* Queue waiters for idle engine */ -+ wait_queue_head_t tx_wait; -+ wait_queue_head_t rx_wait; -+ struct kernfs_node *kn; -+ struct bin_attribute bin; -+ int index; -+ struct aspeed_pci_bmc_dev *pci_bmc_device; ++static const struct pinmux_ops aspeed_g7_soc1_pinmux_ops = { ++ .get_functions_count = aspeed_pinmux_get_fn_count, ++ .get_function_name = aspeed_pinmux_get_fn_name, ++ .get_function_groups = aspeed_pinmux_get_fn_groups, ++ .set_mux = aspeed_g7_pinmux_set_mux, ++ .gpio_request_enable = aspeed_g7_gpio_request_enable, ++ .strict = true, +}; + -+struct aspeed_pcie_mmbi { -+ resource_size_t base; -+ resource_size_t mem_size; -+ void __iomem *mem; -+ u32 segment_size; -+ int irq; -+ int id; -+ struct aspeed_mmbi_channel chan; -+ const char *dev_name; ++static const struct pinconf_ops aspeed_g7_soc1_pinconf_ops = { ++ .is_generic = true, ++ .pin_config_get = aspeed_pin_config_get, ++ .pin_config_set = aspeed_pin_config_set, ++ .pin_config_group_get = aspeed_pin_config_group_get, ++ .pin_config_group_set = aspeed_pin_config_group_set, +}; + -+struct aspeed_pci_bmc_dev { -+ struct device *dev; -+ struct miscdevice miscdev; -+ struct aspeed_platform *platform; -+ kernel_ulong_t driver_data; -+ int id; -+ -+ unsigned long mem_bar_base; -+ unsigned long mem_bar_size; -+ void __iomem *mem_bar_reg; -+ -+ unsigned long message_bar_base; -+ unsigned long message_bar_size; -+ void __iomem *msg_bar_reg; -+ -+ void __iomem *pcie_sio_decode_addr; -+ -+ struct aspeed_queue_message queue[ASPEED_QUEUE_NUM]; ++/* pinctrl_desc */ ++static struct pinctrl_desc aspeed_g7_soc1_pinctrl_desc = { ++ .name = "aspeed-g7-soc1-pinctrl", ++ .pins = aspeed_g7_soc1_pins, ++ .npins = ARRAY_SIZE(aspeed_g7_soc1_pins), ++ .pctlops = &aspeed_g7_soc1_pinctrl_ops, ++ .pmxops = &aspeed_g7_soc1_pinmux_ops, ++ .confops = &aspeed_g7_soc1_pinconf_ops, ++ .owner = THIS_MODULE, ++}; + -+ void __iomem *sio_mbox_reg; -+ struct uart_8250_port uart[VUART_MAX_PARMS]; -+ int uart_line[VUART_MAX_PARMS]; ++static struct aspeed_pin_config aspeed_g7_configs[] = { ++ /* GPIOA */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { C16, C16 }, SCU4C0, GENMASK(1, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C14, C14 }, SCU4C0, GENMASK(3, 2) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C11, C11 }, SCU4C0, GENMASK(5, 4) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { D9, D9 }, SCU4C0, GENMASK(7, 6) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { F14, F14 }, SCU4C0, GENMASK(9, 8) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { D10, D10 }, SCU4C0, GENMASK(11, 10) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C12, C12 }, SCU4C0, GENMASK(13, 12) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C13, C13 }, SCU4C0, GENMASK(15, 14) }, ++ { PIN_CONFIG_POWER_SOURCE, { C16, C13 }, SCU4A0, BIT_MASK(4) }, ++ /* GPIOI */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { W25, W25 }, SCU4C0, GENMASK(17, 16) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { Y23, Y23 }, SCU4C0, GENMASK(19, 18) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { Y24, Y24 }, SCU4C0, GENMASK(21, 20) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { W21, W21 }, SCU4C0, GENMASK(23, 22) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AA23, AA23 }, SCU4C0, GENMASK(25, 24) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AC22, AC22 }, SCU4C0, GENMASK(27, 26) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AB22, AB22 }, SCU4C0, GENMASK(29, 28) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { Y21, Y21 }, SCU4C0, GENMASK(31, 30) }, ++ { PIN_CONFIG_POWER_SOURCE, { W25, Y21 }, SCU4A0, BIT_MASK(12) }, ++ /* GPIOJ */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { AE20, AE20 }, SCU4C4, GENMASK(1, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AF19, AF19 }, SCU4C4, GENMASK(3, 2) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { Y22, Y22 }, SCU4C4, GENMASK(5, 4) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AA20, AA20 }, SCU4C4, GENMASK(7, 6) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AA22, AA22 }, SCU4C4, GENMASK(9, 8) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AB20, AB20 }, SCU4C4, GENMASK(11, 10) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AF18, AF18 }, SCU4C4, GENMASK(13, 12) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AE19, AE19 }, SCU4C4, GENMASK(15, 14) }, ++ /* GPIOK */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { AD20, AD20 }, SCU4C4, GENMASK(17, 16) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AC20, AC20 }, SCU4C4, GENMASK(19, 18) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AA21, AA21 }, SCU4C4, GENMASK(21, 20) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AB21, AB21 }, SCU4C4, GENMASK(23, 22) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AC19, AC19 }, SCU4C4, GENMASK(25, 24) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AE18, AE18 }, SCU4C4, GENMASK(27, 26) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AD19, AD19 }, SCU4C4, GENMASK(29, 28) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AD18, AD18 }, SCU4C4, GENMASK(31, 30) }, ++ /* GPIOL */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { U25, U25 }, SCU4C8, GENMASK(1, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { U26, U26 }, SCU4C8, GENMASK(3, 2) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { Y26, Y26 }, SCU4C8, GENMASK(5, 4) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AA24, AA24 }, SCU4C8, GENMASK(7, 6) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { R25, R25 }, SCU4C8, GENMASK(9, 8) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { AA26, AA26 }, SCU4C8, GENMASK(11, 10) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { R26, R26 }, SCU4C8, GENMASK(13, 12) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { Y25, Y25 }, SCU4C8, GENMASK(15, 14) }, ++ { PIN_CONFIG_POWER_SOURCE, { U25, Y25 }, SCU4A0, BIT_MASK(15) }, ++ /* GPIOM */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { B16, B16 }, SCU4C8, GENMASK(17, 16) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { D14, D14 }, SCU4C8, GENMASK(19, 18) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B15, B15 }, SCU4C8, GENMASK(21, 20) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B14, B14 }, SCU4C8, GENMASK(23, 22) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C17, C17 }, SCU4C8, GENMASK(25, 24) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B13, B13 }, SCU4C8, GENMASK(27, 26) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { E14, E14 }, SCU4C8, GENMASK(29, 28) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C15, C15 }, SCU4C8, GENMASK(31, 30) }, ++ { PIN_CONFIG_POWER_SOURCE, { B16, C15 }, SCU4A0, BIT_MASK(16) }, ++ /* GPION */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { D24, D24 }, SCU4CC, GENMASK(1, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B23, B23 }, SCU4CC, GENMASK(3, 2) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B22, B22 }, SCU4CC, GENMASK(5, 4) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C23, C23 }, SCU4CC, GENMASK(7, 6) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B18, B18 }, SCU4CC, GENMASK(9, 8) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B21, B21 }, SCU4CC, GENMASK(11, 10) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { M15, M15 }, SCU4CC, GENMASK(13, 12) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B19, B19 }, SCU4CC, GENMASK(15, 14) }, ++ { PIN_CONFIG_POWER_SOURCE, { D24, B19 }, SCU4A0, BIT_MASK(17) }, ++ /* GPIOO */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { B26, B26 }, SCU4CC, GENMASK(17, 16) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A25, A25 }, SCU4CC, GENMASK(19, 18) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A24, A24 }, SCU4CC, GENMASK(21, 20) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B24, B24 }, SCU4CC, GENMASK(23, 22) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { E26, E26 }, SCU4CC, GENMASK(25, 24) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A21, A21 }, SCU4CC, GENMASK(27, 26) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A19, A19 }, SCU4CC, GENMASK(29, 28) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A18, A18 }, SCU4CC, GENMASK(31, 30) }, ++ { PIN_CONFIG_POWER_SOURCE, { B26, A18 }, SCU4A0, BIT_MASK(18) }, ++ /* GPIOP */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { D26, D26 }, SCU4D0, GENMASK(1, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C26, C26 }, SCU4D0, GENMASK(3, 2) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A23, A23 }, SCU4D0, GENMASK(5, 4) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A22, A22 }, SCU4D0, GENMASK(7, 6) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B25, B25 }, SCU4D0, GENMASK(9, 8) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { F26, F26 }, SCU4D0, GENMASK(11, 10) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A26, A26 }, SCU4D0, GENMASK(13, 12) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A14, A14 }, SCU4D0, GENMASK(15, 14) }, ++ { PIN_CONFIG_POWER_SOURCE, { D26, A14 }, SCU4A0, BIT_MASK(19) }, ++ /* GPIOQ */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { E10, E10 }, SCU4D0, GENMASK(17, 16) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { E13, E13 }, SCU4D0, GENMASK(19, 18) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { D12, D12 }, SCU4D0, GENMASK(21, 20) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { F10, F10 }, SCU4D0, GENMASK(23, 22) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { E11, E11 }, SCU4D0, GENMASK(25, 24) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { F11, F11 }, SCU4D0, GENMASK(27, 26) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { F13, F13 }, SCU4D0, GENMASK(29, 28) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { N15, N15 }, SCU4D0, GENMASK(31, 30) }, ++ /* GPIOR */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { C20, C20 }, SCU4D4, GENMASK(1, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C19, C19 }, SCU4D4, GENMASK(3, 2) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A8, A8 }, SCU4D4, GENMASK(5, 4) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { R14, R14 }, SCU4D4, GENMASK(7, 6) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A7, A7 }, SCU4D4, GENMASK(9, 8) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { P14, P14 }, SCU4D4, GENMASK(11, 10) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { D20, D20 }, SCU4D4, GENMASK(13, 12) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A6, A6 }, SCU4D4, GENMASK(15, 14) }, ++ { PIN_CONFIG_POWER_SOURCE, { C20, A6 }, SCU4A0, BIT_MASK(21) }, ++ /* GPIOS */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { B6, B6 }, SCU4D4, GENMASK(17, 16) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { N14, N14 }, SCU4D4, GENMASK(19, 18) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B7, B7 }, SCU4D4, GENMASK(21, 20) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B8, B8 }, SCU4D4, GENMASK(23, 22) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B9, B9 }, SCU4D4, GENMASK(25, 24) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { M14, M14 }, SCU4D4, GENMASK(27, 26) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { J11, J11 }, SCU4D4, GENMASK(29, 28) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { E7, E7 }, SCU4D4, GENMASK(31, 30) }, ++ { PIN_CONFIG_POWER_SOURCE, { B6, E7 }, SCU4A0, BIT_MASK(22) }, ++ /* GPIOT */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { D19, D19 }, SCU4D8, GENMASK(1, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B11, B11 }, SCU4D8, GENMASK(3, 2) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { D15, D15 }, SCU4D8, GENMASK(5, 4) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B12, B12 }, SCU4D8, GENMASK(7, 6) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { B10, B10 }, SCU4D8, GENMASK(9, 8) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { P13, P13 }, SCU4D8, GENMASK(11, 10) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C18, C18 }, SCU4D8, GENMASK(13, 12) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C6, C6 }, SCU4D8, GENMASK(15, 14) }, ++ { PIN_CONFIG_POWER_SOURCE, { D19, C6 }, SCU4A0, BIT_MASK(23) }, ++ /* GPIOU */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { C7, C7 }, SCU4D8, GENMASK(17, 16) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { D7, D7 }, SCU4D8, GENMASK(19, 18) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { N13, N13 }, SCU4D8, GENMASK(21, 20) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C8, C8 }, SCU4D8, GENMASK(23, 22) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C9, C9 }, SCU4D8, GENMASK(25, 24) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { C10, C10 }, SCU4D8, GENMASK(27, 26) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { M16, M16 }, SCU4D8, GENMASK(29, 28) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { A15, A15 }, SCU4D8, GENMASK(31, 30) }, ++ { PIN_CONFIG_POWER_SOURCE, { C7, A15 }, SCU4A0, BIT_MASK(24) }, ++ /* GPIOW */ ++ { PIN_CONFIG_DRIVE_STRENGTH, { E9, E9 }, SCU4DC, GENMASK(1, 0) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { F9, F9 }, SCU4DC, GENMASK(3, 2) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { F8, F8 }, SCU4DC, GENMASK(5, 4) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { M13, M13 }, SCU4DC, GENMASK(7, 6) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { F7, F7 }, SCU4DC, GENMASK(9, 8) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { D8, D8 }, SCU4DC, GENMASK(11, 10) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { E8, E8 }, SCU4DC, GENMASK(13, 12) }, ++ { PIN_CONFIG_DRIVE_STRENGTH, { L12, L12 }, SCU4DC, GENMASK(15, 14) }, ++ { PIN_CONFIG_POWER_SOURCE, { E9, L12 }, SCU4A0, BIT_MASK(26) }, + -+ /* Interrupt -+ * The index of array is using to enum msi_index -+ */ -+ int *msi_idx_table; ++ ASPEED_PULL_DOWN_PINCONF(C16, SCU480, 0), ++ ASPEED_PULL_DOWN_PINCONF(C14, SCU480, 1), ++ ASPEED_PULL_DOWN_PINCONF(C11, SCU480, 2), ++ ASPEED_PULL_DOWN_PINCONF(D9, SCU480, 3), ++ ASPEED_PULL_DOWN_PINCONF(F14, SCU480, 4), ++ ASPEED_PULL_DOWN_PINCONF(D10, SCU480, 5), ++ ASPEED_PULL_DOWN_PINCONF(C12, SCU480, 6), ++ ASPEED_PULL_DOWN_PINCONF(C13, SCU480, 7), ++ ASPEED_PULL_DOWN_PINCONF(AC26, SCU480, 8), ++ ASPEED_PULL_DOWN_PINCONF(AA25, SCU480, 9), ++ ASPEED_PULL_DOWN_PINCONF(AB23, SCU480, 10), ++ ASPEED_PULL_DOWN_PINCONF(U22, SCU480, 11), ++ ASPEED_PULL_DOWN_PINCONF(V21, SCU480, 12), ++ ASPEED_PULL_DOWN_PINCONF(N26, SCU480, 13), ++ ASPEED_PULL_DOWN_PINCONF(P25, SCU480, 14), ++ ASPEED_PULL_DOWN_PINCONF(N25, SCU480, 15), ++ ASPEED_PULL_DOWN_PINCONF(V23, SCU480, 16), ++ ASPEED_PULL_DOWN_PINCONF(W22, SCU480, 17), ++ ASPEED_PULL_DOWN_PINCONF(AB26, SCU480, 18), ++ ASPEED_PULL_DOWN_PINCONF(AD26, SCU480, 19), ++ ASPEED_PULL_DOWN_PINCONF(P26, SCU480, 20), ++ ASPEED_PULL_DOWN_PINCONF(AE26, SCU480, 21), ++ ASPEED_PULL_DOWN_PINCONF(AF26, SCU480, 22), ++ ASPEED_PULL_DOWN_PINCONF(AF25, SCU480, 23), ++ ASPEED_PULL_DOWN_PINCONF(AE25, SCU480, 24), ++ ASPEED_PULL_DOWN_PINCONF(AD25, SCU480, 25), ++ ASPEED_PULL_DOWN_PINCONF(AF23, SCU480, 26), ++ ASPEED_PULL_DOWN_PINCONF(AF20, SCU480, 27), ++ ASPEED_PULL_DOWN_PINCONF(AF21, SCU480, 28), ++ ASPEED_PULL_DOWN_PINCONF(AE21, SCU480, 29), ++ ASPEED_PULL_DOWN_PINCONF(AE23, SCU480, 30), ++ ASPEED_PULL_DOWN_PINCONF(AD22, SCU480, 31), ++ ASPEED_PULL_DOWN_PINCONF(AF17, SCU484, 0), ++ ASPEED_PULL_DOWN_PINCONF(AA16, SCU484, 1), ++ ASPEED_PULL_DOWN_PINCONF(Y16, SCU484, 2), ++ ASPEED_PULL_DOWN_PINCONF(V17, SCU484, 3), ++ ASPEED_PULL_DOWN_PINCONF(J13, SCU484, 4), ++ ASPEED_PULL_DOWN_PINCONF(AB16, SCU484, 5), ++ ASPEED_PULL_DOWN_PINCONF(AC16, SCU484, 6), ++ ASPEED_PULL_DOWN_PINCONF(AF16, SCU484, 7), ++ ASPEED_PULL_DOWN_PINCONF(AA15, SCU484, 8), ++ ASPEED_PULL_DOWN_PINCONF(AB15, SCU484, 9), ++ ASPEED_PULL_DOWN_PINCONF(AC15, SCU484, 10), ++ ASPEED_PULL_DOWN_PINCONF(AD15, SCU484, 11), ++ ASPEED_PULL_DOWN_PINCONF(Y15, SCU484, 12), ++ ASPEED_PULL_DOWN_PINCONF(AA14, SCU484, 13), ++ ASPEED_PULL_DOWN_PINCONF(W16, SCU484, 14), ++ ASPEED_PULL_DOWN_PINCONF(V16, SCU484, 15), ++ ASPEED_PULL_DOWN_PINCONF(AB18, SCU484, 16), ++ ASPEED_PULL_DOWN_PINCONF(AC18, SCU484, 17), ++ ASPEED_PULL_DOWN_PINCONF(K13, SCU484, 18), ++ ASPEED_PULL_DOWN_PINCONF(AA17, SCU484, 19), ++ ASPEED_PULL_DOWN_PINCONF(AB17, SCU484, 20), ++ ASPEED_PULL_DOWN_PINCONF(AD16, SCU484, 21), ++ ASPEED_PULL_DOWN_PINCONF(AC17, SCU484, 22), ++ ASPEED_PULL_DOWN_PINCONF(AD17, SCU484, 23), ++ ASPEED_PULL_DOWN_PINCONF(AE16, SCU484, 24), ++ ASPEED_PULL_DOWN_PINCONF(AE17, SCU484, 25), ++ ASPEED_PULL_DOWN_PINCONF(AB24, SCU484, 26), ++ ASPEED_PULL_DOWN_PINCONF(W26, SCU484, 27), ++ ASPEED_PULL_DOWN_PINCONF(HOLE0, SCU484, 28), ++ ASPEED_PULL_DOWN_PINCONF(HOLE1, SCU484, 29), ++ ASPEED_PULL_DOWN_PINCONF(HOLE2, SCU484, 30), ++ ASPEED_PULL_DOWN_PINCONF(HOLE3, SCU484, 31), ++ ASPEED_PULL_DOWN_PINCONF(W25, SCU488, 0), ++ ASPEED_PULL_DOWN_PINCONF(Y23, SCU488, 1), ++ ASPEED_PULL_DOWN_PINCONF(Y24, SCU488, 2), ++ ASPEED_PULL_DOWN_PINCONF(W21, SCU488, 3), ++ ASPEED_PULL_DOWN_PINCONF(AA23, SCU488, 4), ++ ASPEED_PULL_DOWN_PINCONF(AC22, SCU488, 5), ++ ASPEED_PULL_DOWN_PINCONF(AB22, SCU488, 6), ++ ASPEED_PULL_DOWN_PINCONF(Y21, SCU488, 7), ++ ASPEED_PULL_DOWN_PINCONF(AE20, SCU488, 8), ++ ASPEED_PULL_DOWN_PINCONF(AF19, SCU488, 9), ++ ASPEED_PULL_DOWN_PINCONF(Y22, SCU488, 10), ++ ASPEED_PULL_DOWN_PINCONF(AA20, SCU488, 11), ++ ASPEED_PULL_DOWN_PINCONF(AA22, SCU488, 12), ++ ASPEED_PULL_DOWN_PINCONF(AB20, SCU488, 13), ++ ASPEED_PULL_DOWN_PINCONF(AF18, SCU488, 14), ++ ASPEED_PULL_DOWN_PINCONF(AE19, SCU488, 15), ++ ASPEED_PULL_DOWN_PINCONF(AD20, SCU488, 16), ++ ASPEED_PULL_DOWN_PINCONF(AC20, SCU488, 17), ++ ASPEED_PULL_DOWN_PINCONF(AA21, SCU488, 18), ++ ASPEED_PULL_DOWN_PINCONF(AB21, SCU488, 19), ++ ASPEED_PULL_DOWN_PINCONF(AC19, SCU488, 20), ++ ASPEED_PULL_DOWN_PINCONF(AE18, SCU488, 21), ++ ASPEED_PULL_DOWN_PINCONF(AD19, SCU488, 22), ++ ASPEED_PULL_DOWN_PINCONF(AD18, SCU488, 23), ++ ASPEED_PULL_DOWN_PINCONF(U25, SCU488, 24), ++ ASPEED_PULL_DOWN_PINCONF(U26, SCU488, 25), ++ ASPEED_PULL_DOWN_PINCONF(Y26, SCU488, 26), ++ ASPEED_PULL_DOWN_PINCONF(AA24, SCU488, 27), ++ ASPEED_PULL_DOWN_PINCONF(R25, SCU488, 28), ++ ASPEED_PULL_DOWN_PINCONF(AA26, SCU488, 29), ++ ASPEED_PULL_DOWN_PINCONF(R26, SCU488, 30), ++ ASPEED_PULL_DOWN_PINCONF(Y25, SCU488, 31), ++ ASPEED_PULL_DOWN_PINCONF(B16, SCU48C, 0), ++ ASPEED_PULL_DOWN_PINCONF(D14, SCU48C, 1), ++ ASPEED_PULL_DOWN_PINCONF(B15, SCU48C, 2), ++ ASPEED_PULL_DOWN_PINCONF(B14, SCU48C, 3), ++ ASPEED_PULL_DOWN_PINCONF(C17, SCU48C, 4), ++ ASPEED_PULL_DOWN_PINCONF(B13, SCU48C, 5), ++ ASPEED_PULL_DOWN_PINCONF(E14, SCU48C, 6), ++ ASPEED_PULL_DOWN_PINCONF(C15, SCU48C, 7), ++ ASPEED_PULL_DOWN_PINCONF(D24, SCU48C, 8), ++ ASPEED_PULL_DOWN_PINCONF(B23, SCU48C, 9), ++ ASPEED_PULL_DOWN_PINCONF(B22, SCU48C, 10), ++ ASPEED_PULL_DOWN_PINCONF(C23, SCU48C, 11), ++ ASPEED_PULL_DOWN_PINCONF(B18, SCU48C, 12), ++ ASPEED_PULL_DOWN_PINCONF(B21, SCU48C, 13), ++ ASPEED_PULL_DOWN_PINCONF(M15, SCU48C, 14), ++ ASPEED_PULL_DOWN_PINCONF(B19, SCU48C, 15), ++ ASPEED_PULL_DOWN_PINCONF(B26, SCU48C, 16), ++ ASPEED_PULL_DOWN_PINCONF(A25, SCU48C, 17), ++ ASPEED_PULL_DOWN_PINCONF(A24, SCU48C, 18), ++ ASPEED_PULL_DOWN_PINCONF(B24, SCU48C, 19), ++ ASPEED_PULL_DOWN_PINCONF(E26, SCU48C, 20), ++ ASPEED_PULL_DOWN_PINCONF(A21, SCU48C, 21), ++ ASPEED_PULL_DOWN_PINCONF(A19, SCU48C, 22), ++ ASPEED_PULL_DOWN_PINCONF(A18, SCU48C, 23), ++ ASPEED_PULL_DOWN_PINCONF(D26, SCU48C, 24), ++ ASPEED_PULL_DOWN_PINCONF(C26, SCU48C, 25), ++ ASPEED_PULL_DOWN_PINCONF(A23, SCU48C, 26), ++ ASPEED_PULL_DOWN_PINCONF(A22, SCU48C, 27), ++ ASPEED_PULL_DOWN_PINCONF(B25, SCU48C, 28), ++ ASPEED_PULL_DOWN_PINCONF(F26, SCU48C, 29), ++ ASPEED_PULL_DOWN_PINCONF(A26, SCU48C, 30), ++ ASPEED_PULL_DOWN_PINCONF(A14, SCU48C, 31), ++ ASPEED_PULL_DOWN_PINCONF(E10, SCU490, 0), ++ ASPEED_PULL_DOWN_PINCONF(E13, SCU490, 1), ++ ASPEED_PULL_DOWN_PINCONF(D12, SCU490, 2), ++ ASPEED_PULL_DOWN_PINCONF(F10, SCU490, 3), ++ ASPEED_PULL_DOWN_PINCONF(E11, SCU490, 4), ++ ASPEED_PULL_DOWN_PINCONF(F11, SCU490, 5), ++ ASPEED_PULL_DOWN_PINCONF(F13, SCU490, 6), ++ ASPEED_PULL_DOWN_PINCONF(N15, SCU490, 7), ++ ASPEED_PULL_DOWN_PINCONF(C20, SCU490, 8), ++ ASPEED_PULL_DOWN_PINCONF(C19, SCU490, 9), ++ ASPEED_PULL_DOWN_PINCONF(A8, SCU490, 10), ++ ASPEED_PULL_DOWN_PINCONF(R14, SCU490, 11), ++ ASPEED_PULL_DOWN_PINCONF(A7, SCU490, 12), ++ ASPEED_PULL_DOWN_PINCONF(P14, SCU490, 13), ++ ASPEED_PULL_DOWN_PINCONF(D20, SCU490, 14), ++ ASPEED_PULL_DOWN_PINCONF(A6, SCU490, 15), ++ ASPEED_PULL_DOWN_PINCONF(B6, SCU490, 16), ++ ASPEED_PULL_DOWN_PINCONF(N14, SCU490, 17), ++ ASPEED_PULL_DOWN_PINCONF(B7, SCU490, 18), ++ ASPEED_PULL_DOWN_PINCONF(B8, SCU490, 19), ++ ASPEED_PULL_DOWN_PINCONF(B9, SCU490, 20), ++ ASPEED_PULL_DOWN_PINCONF(M14, SCU490, 21), ++ ASPEED_PULL_DOWN_PINCONF(J11, SCU490, 22), ++ ASPEED_PULL_DOWN_PINCONF(E7, SCU490, 23), ++ ASPEED_PULL_DOWN_PINCONF(D19, SCU490, 24), ++ ASPEED_PULL_DOWN_PINCONF(B11, SCU490, 25), ++ ASPEED_PULL_DOWN_PINCONF(D15, SCU490, 26), ++ ASPEED_PULL_DOWN_PINCONF(B12, SCU490, 27), ++ ASPEED_PULL_DOWN_PINCONF(B10, SCU490, 28), ++ ASPEED_PULL_DOWN_PINCONF(P13, SCU490, 29), ++ ASPEED_PULL_DOWN_PINCONF(C18, SCU490, 30), ++ ASPEED_PULL_DOWN_PINCONF(C6, SCU490, 31), ++ ASPEED_PULL_DOWN_PINCONF(C7, SCU494, 0), ++ ASPEED_PULL_DOWN_PINCONF(D7, SCU494, 1), ++ ASPEED_PULL_DOWN_PINCONF(N13, SCU494, 2), ++ ASPEED_PULL_DOWN_PINCONF(C8, SCU494, 3), ++ ASPEED_PULL_DOWN_PINCONF(C9, SCU494, 4), ++ ASPEED_PULL_DOWN_PINCONF(C10, SCU494, 5), ++ ASPEED_PULL_DOWN_PINCONF(M16, SCU494, 6), ++ ASPEED_PULL_DOWN_PINCONF(A15, SCU494, 7), ++ ASPEED_PULL_DOWN_PINCONF(G11, SCU494, 8), ++ ASPEED_PULL_DOWN_PINCONF(H7, SCU494, 9), ++ ASPEED_PULL_DOWN_PINCONF(H8, SCU494, 10), ++ ASPEED_PULL_DOWN_PINCONF(H9, SCU494, 11), ++ ASPEED_PULL_DOWN_PINCONF(H10, SCU494, 12), ++ ASPEED_PULL_DOWN_PINCONF(H11, SCU494, 13), ++ ASPEED_PULL_DOWN_PINCONF(J9, SCU494, 14), ++ ASPEED_PULL_DOWN_PINCONF(J10, SCU494, 15), ++ ASPEED_PULL_DOWN_PINCONF(E9, SCU494, 16), ++ ASPEED_PULL_DOWN_PINCONF(F9, SCU494, 17), ++ ASPEED_PULL_DOWN_PINCONF(F8, SCU494, 18), ++ ASPEED_PULL_DOWN_PINCONF(M13, SCU494, 19), ++ ASPEED_PULL_DOWN_PINCONF(F7, SCU494, 20), ++ ASPEED_PULL_DOWN_PINCONF(D8, SCU494, 21), ++ ASPEED_PULL_DOWN_PINCONF(E8, SCU494, 22), ++ ASPEED_PULL_DOWN_PINCONF(L12, SCU494, 23), ++ ASPEED_PULL_DOWN_PINCONF(F12, SCU494, 24), ++ ASPEED_PULL_DOWN_PINCONF(E12, SCU494, 25), ++ ASPEED_PULL_DOWN_PINCONF(J12, SCU494, 26), ++ ASPEED_PULL_DOWN_PINCONF(G7, SCU494, 27), ++ ASPEED_PULL_DOWN_PINCONF(G8, SCU494, 28), ++ ASPEED_PULL_DOWN_PINCONF(G9, SCU494, 29), ++ ASPEED_PULL_DOWN_PINCONF(G10, SCU494, 30), ++ ASPEED_PULL_DOWN_PINCONF(K12, SCU494, 31), ++ ASPEED_PULL_DOWN_PINCONF(W17, SCU498, 0), ++ ASPEED_PULL_DOWN_PINCONF(V18, SCU498, 1), ++ ASPEED_PULL_DOWN_PINCONF(W18, SCU498, 2), ++ ASPEED_PULL_DOWN_PINCONF(Y17, SCU498, 3), ++ ASPEED_PULL_DOWN_PINCONF(AA18, SCU498, 4), ++ ASPEED_PULL_DOWN_PINCONF(AA13, SCU498, 5), ++ ASPEED_PULL_DOWN_PINCONF(Y18, SCU498, 6), ++ ASPEED_PULL_DOWN_PINCONF(AA12, SCU498, 7), ++ ASPEED_PULL_DOWN_PINCONF(W20, SCU498, 8), ++ ASPEED_PULL_DOWN_PINCONF(V20, SCU498, 9), ++ ASPEED_PULL_DOWN_PINCONF(Y11, SCU498, 10), ++ ASPEED_PULL_DOWN_PINCONF(V14, SCU498, 11), ++ ASPEED_PULL_DOWN_PINCONF(V19, SCU498, 12), ++ ASPEED_PULL_DOWN_PINCONF(W14, SCU498, 13), ++ ASPEED_PULL_DOWN_PINCONF(Y20, SCU498, 14), ++ ASPEED_PULL_DOWN_PINCONF(AB19, SCU498, 15), ++ ASPEED_PULL_DOWN_PINCONF(U21, SCU498, 16), ++ ASPEED_PULL_DOWN_PINCONF(T24, SCU498, 17), ++ ASPEED_PULL_DOWN_PINCONF(V24, SCU498, 18), ++ ASPEED_PULL_DOWN_PINCONF(V22, SCU498, 19), ++ ASPEED_PULL_DOWN_PINCONF(T23, SCU498, 20), ++ ASPEED_PULL_DOWN_PINCONF(AC25, SCU498, 21), ++ ASPEED_PULL_DOWN_PINCONF(AB25, SCU498, 22), ++ ASPEED_PULL_DOWN_PINCONF(AC24, SCU498, 23), ++}; + -+ bool ast2700_soc1; ++static const struct aspeed_pin_config_map aspeed_g7_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)}, ++}; + -+ /* AST2700 MMBI */ -+ struct aspeed_pcie_mmbi mmbi[MMBI_MAX_INST]; -+ int mmbi_start_msi; ++static struct aspeed_pinctrl_data aspeed_g7_pinctrl_data = { ++ .pins = aspeed_g7_soc1_pins, ++ .npins = ARRAY_SIZE(aspeed_g7_soc1_pins), ++ .pinmux = { ++ .groups = aspeed_g7_soc1_pingroups, ++ .ngroups = ARRAY_SIZE(aspeed_g7_soc1_pingroups), ++ .functions = aspeed_g7_soc1_funcs, ++ .nfunctions = ARRAY_SIZE(aspeed_g7_soc1_funcs), ++ .configs_g7 = pin_cfg, ++ .nconfigs_g7 = ARRAY_SIZE(pin_cfg), ++ }, ++ .configs = aspeed_g7_configs, ++ .nconfigs = ARRAY_SIZE(aspeed_g7_configs), ++ .confmaps = aspeed_g7_pin_config_map, ++ .nconfmaps = ARRAY_SIZE(aspeed_g7_pin_config_map), +}; + -+#define PCIE_DEVICE_SIO_ADDR (0x2E * 4) -+#define BMC_MULTI_MSI 32 ++static int aspeed_g7_soc1_pinctrl_probe(struct platform_device *pdev) ++{ ++ return aspeed_pinctrl_probe(pdev, &aspeed_g7_soc1_pinctrl_desc, ++ &aspeed_g7_pinctrl_data); ++} + -+#define DRIVER_NAME "aspeed-host-bmc-dev" ++static const struct of_device_id aspeed_g7_soc1_pinctrl_match[] = { ++ { .compatible = "aspeed,ast2700-soc1-pinctrl" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, aspeed_g7_soc1_pinctrl_match); + -+static int mmbi_desc_init(struct aspeed_mmbi_channel *chan); ++static struct platform_driver aspeed_g7_soc1_pinctrl_driver = { ++ .probe = aspeed_g7_soc1_pinctrl_probe, ++ .driver = { ++ .name = "aspeed-g7-soc1-pinctrl", ++ .of_match_table = aspeed_g7_soc1_pinctrl_match, ++ .suppress_bind_attrs = true, ++ }, ++}; + -+static u8 mmbi_get_bmc_rdy(struct aspeed_mmbi_channel *chan) ++static int __init aspeed_g7_soc1_pinctrl_register(void) +{ -+ struct host_ros hros; -+ -+ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); -+ -+ return hros.b_rdy; ++ return platform_driver_register(&aspeed_g7_soc1_pinctrl_driver); +} -+ -+static u8 mmbi_get_bmc_up(struct aspeed_mmbi_channel *chan) ++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 +@@ -285,6 +285,32 @@ + return 0; + } + ++int aspeed_g7_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function, ++ unsigned int group) +{ -+ struct host_ros hros; ++ int i, j; ++ int pin; ++ const struct aspeed_g7_funcfg *funcfg; ++ struct aspeed_pinctrl_data *pinctrl = pinctrl_dev_get_drvdata(pctldev); ++ const struct aspeed_pin_group *pingroup = ++ &pinctrl->pinmux.groups[group]; ++ const struct aspeed_g7_pincfg *pin_cfg = pinctrl->pinmux.configs_g7; + -+ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); ++ for (i = 0; i < pingroup->npins; i++) { ++ pin = pingroup->pins[i]; ++ funcfg = pin_cfg[pin].funcfg; + -+ return hros.b_up; ++ for (j = 0; j < pin_cfg[pin].nfuncfg; j++) { ++ if (strcmp(funcfg[j].name, pingroup->name) == 0) { ++ regmap_update_bits(pinctrl->scu, funcfg[j].reg, ++ funcfg[j].mask, ++ funcfg[j].val); ++ } ++ } ++ } ++ return 0; +} + -+static u8 mmbi_get_bmc_rst(struct aspeed_mmbi_channel *chan) + static bool aspeed_expr_is_gpio(const struct aspeed_sig_expr *expr) + { + /* +@@ -440,6 +466,27 @@ + return 0; + } + ++int aspeed_g7_gpio_request_enable(struct pinctrl_dev *pctldev, ++ struct pinctrl_gpio_range *range, ++ unsigned int offset) +{ -+ struct host_ros hros; -+ -+ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); ++ int i; ++ struct aspeed_pinctrl_data *pinctrl = pinctrl_dev_get_drvdata(pctldev); ++ const struct aspeed_g7_pincfg *pin_cfg = pinctrl->pinmux.configs_g7; ++ const struct aspeed_g7_funcfg *funcfg = pin_cfg[offset].funcfg; + -+ return hros.b_rst; ++ for (i = 0; i < pin_cfg[offset].nfuncfg; i++) { ++ if (!strncmp(funcfg[i].name, "GPI", 3)) { ++ regmap_update_bits(pinctrl->scu, funcfg[i].reg, ++ funcfg[i].mask, funcfg[i].val); ++ break; ++ } ++ regmap_update_bits(pinctrl->scu, funcfg[i].reg, funcfg[i].mask, ++ 0); ++ } ++ return 0; +} + -+static u8 mmbi_get_host_rst(struct aspeed_mmbi_channel *chan) -+{ -+ struct host_rws hrws; -+ -+ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); + int aspeed_pinctrl_probe(struct platform_device *pdev, + 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 +@@ -70,15 +70,15 @@ + struct regmap *scu; + + const struct pinctrl_pin_desc *pins; +- const unsigned int npins; ++ unsigned int npins; + + const struct aspeed_pin_config *configs; +- const unsigned int nconfigs; ++ unsigned int nconfigs; + + struct aspeed_pinmux_data pinmux; + + const struct aspeed_pin_config_map *confmaps; +- const unsigned int nconfmaps; ++ unsigned int nconfmaps; + }; + + /* Aspeed pinctrl helpers */ +@@ -101,6 +101,11 @@ + int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset); ++int aspeed_g7_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function, ++ unsigned int group); ++int aspeed_g7_gpio_request_enable(struct pinctrl_dev *pctldev, ++ struct pinctrl_gpio_range *range, ++ unsigned int offset); + int aspeed_pinctrl_probe(struct platform_device *pdev, + 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 +@@ -792,6 +792,33 @@ + const struct aspeed_sig_expr *expr, bool enabled); + }; + ++struct aspeed_g7_funcfg { ++ char *name; ++ u32 reg; ++ u32 mask; ++ int val; ++}; + -+ return hrws.h_rst; -+} ++struct aspeed_g7_pincfg { ++ struct aspeed_g7_funcfg *funcfg; ++ unsigned int nfuncfg; ++}; + -+static u8 mmbi_get_host_up(struct aspeed_mmbi_channel *chan) -+{ -+ struct host_rws hrws; ++#define PIN_CFG(cfg_name, cfg_reg, cfg_mask, cfg_val) \ ++ { \ ++ .name = #cfg_name, .reg = cfg_reg, .mask = cfg_mask, \ ++ .val = cfg_val \ ++ } ++#define FUNCFG_SYM(pin) funcfg_ ## pin ++#define FUNCFG_PTR(pin) (&FUNCFG_SYM(pin)) + -+ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); ++#define FUNCFG_DESCL(pin, ...) \ ++ static const struct aspeed_g7_funcfg FUNCFG_SYM(pin)[] = { __VA_ARGS__ } + -+ return hrws.h_up; -+} ++#define PINCFG_PIN(pin) \ ++ [pin] = { .funcfg = (struct aspeed_g7_funcfg *)FUNCFG_PTR(pin), \ ++ .nfuncfg = ARRAY_SIZE(FUNCFG_SYM(pin)) } + -+static void mmbi_set_host_rst(struct aspeed_mmbi_channel *chan, bool set) -+{ -+ struct host_rws hrws; + struct aspeed_pinmux_data { + struct device *dev; + struct regmap *maps[ASPEED_NR_PINMUX_IPS]; +@@ -799,10 +826,14 @@ + const struct aspeed_pinmux_ops *ops; + + const struct aspeed_pin_group *groups; +- const unsigned int ngroups; ++ unsigned int ngroups; + + const struct aspeed_pin_function *functions; +- const unsigned int nfunctions; ++ unsigned int nfunctions; + -+ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); -+ hrws.h_rst = set; -+ memcpy_toio(chan->hrws_vmem, &hrws, sizeof(hrws)); -+} ++ const struct aspeed_g7_pincfg *configs_g7; ++ unsigned int nconfigs_g7; + -+static void mmbi_set_host_rdy(struct aspeed_mmbi_channel *chan, bool set) -+{ -+ struct host_rws hrws; + }; + + 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. + -+ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); -+ hrws.h_rdy = set; -+ memcpy_toio(chan->hrws_vmem, &hrws, sizeof(hrws)); -+} + config RESET_ATH79 + bool "AR71xx Reset Driver" if COMPILE_TEST + default ATH79 +@@ -51,8 +58,8 @@ + + config RESET_BRCMSTB + tristate "Broadcom STB reset controller" +- depends on ARCH_BRCMSTB || COMPILE_TEST +- default ARCH_BRCMSTB ++ depends on ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST ++ default ARCH_BRCMSTB || ARCH_BCM2835 + help + This enables the reset controller driver for Broadcom STB SoCs using + a SUN_TOP_CTRL_SW_INIT style controller. +@@ -60,11 +67,11 @@ + config RESET_BRCMSTB_RESCAL + tristate "Broadcom STB RESCAL reset controller" + depends on HAS_IOMEM +- depends on ARCH_BRCMSTB || COMPILE_TEST +- default ARCH_BRCMSTB ++ depends on ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST ++ default ARCH_BRCMSTB || ARCH_BCM2835 + help + This enables the RESCAL reset controller for SATA, PCIe0, or PCIe1 on +- BCM7216. ++ BCM7216 or the BCM2712. + + config RESET_EYEQ + bool "Mobileye EyeQ reset controller" +@@ -170,6 +177,7 @@ + config RESET_NPCM + bool "NPCM BMC Reset Driver" if COMPILE_TEST + default ARCH_NPCM ++ select AUXILIARY_BUS + help + This enables the reset controller driver for Nuvoton NPCM + BMC SoCs. +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 +@@ -0,0 +1,310 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2024 ASPEED Technology Inc. ++ */ + -+static void mmbi_set_host_up(struct aspeed_mmbi_channel *chan, bool set) -+{ -+ struct host_rws hrws; ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); -+ hrws.h_up = set; -+ memcpy_toio(chan->hrws_vmem, &hrws, sizeof(hrws)); -+} ++#include ++#include + -+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; ++#define SCU0_RESET_CTRL1 0x200 ++#define SCU0_RESET_CTRL2 0x220 ++#define SCU1_RESET_CTRL1 0x200 ++#define SCU1_RESET_CTRL2 0x220 ++#define SCU1_PCIE3_CTRL 0x908 + -+ 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); ++struct aspeed_reset; + -+ if (h2b_wp >= h2b_rp) -+ *avail_buf_len = chan->h2b_cb_size - h2b_wp + h2b_rp; -+ else -+ *avail_buf_len = h2b_rp - h2b_wp; -+} ++struct ast2700_reset_signal { ++ bool dedicated_clr; /* dedicated reset clr offset */ ++ u32 offset, bit; ++}; + -+static u8 mmbi_get_state(struct aspeed_mmbi_channel *chan) -+{ -+ u8 state = 0; ++struct aspeed_reset_info { ++ unsigned int nr_resets; ++ const struct ast2700_reset_signal *signal; ++}; + -+ 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); ++struct aspeed_reset { ++ struct reset_controller_dev rcdev; ++ struct aspeed_reset_info *info; ++ spinlock_t lock; /* Protect read-modify-write cycle */ ++ void __iomem *base; ++}; + -+ dev_dbg(chan->dev, "MMBI state: 0x%x\n", state); ++static const struct ast2700_reset_signal ast2700_reset0_signals[] = { ++ [SCU0_RESET_SDRAM] = { true, SCU0_RESET_CTRL1, BIT(0) }, ++ [SCU0_RESET_DDRPHY] = { true, SCU0_RESET_CTRL1, BIT(1) }, ++ [SCU0_RESET_RSA] = { true, SCU0_RESET_CTRL1, BIT(2) }, ++ [SCU0_RESET_SHA3] = { true, SCU0_RESET_CTRL1, BIT(3) }, ++ [SCU0_RESET_HACE] = { true, SCU0_RESET_CTRL1, BIT(4) }, ++ [SCU0_RESET_SOC] = { true, SCU0_RESET_CTRL1, BIT(5) }, ++ [SCU0_RESET_VIDEO] = { true, SCU0_RESET_CTRL1, BIT(6) }, ++ [SCU0_RESET_2D] = { true, SCU0_RESET_CTRL1, BIT(7) }, ++ [SCU0_RESET_PCIS] = { true, SCU0_RESET_CTRL1, BIT(8) }, ++ [SCU0_RESET_RVAS0] = { true, SCU0_RESET_CTRL1, BIT(9) }, ++ [SCU0_RESET_RVAS1] = { true, SCU0_RESET_CTRL1, BIT(10) }, ++ [SCU0_RESET_SM3] = { true, SCU0_RESET_CTRL1, BIT(11) }, ++ [SCU0_RESET_SM4] = { true, SCU0_RESET_CTRL1, BIT(12) }, ++ [SCU0_RESET_CRT0] = { true, SCU0_RESET_CTRL1, BIT(13) }, ++ [SCU0_RESET_ECC] = { true, SCU0_RESET_CTRL1, BIT(14) }, ++ [SCU0_RESET_DP_PCI] = { true, SCU0_RESET_CTRL1, BIT(15) }, ++ [SCU0_RESET_UFS] = { true, SCU0_RESET_CTRL1, BIT(16) }, ++ [SCU0_RESET_EMMC] = { true, SCU0_RESET_CTRL1, BIT(17) }, ++ [SCU0_RESET_PCIE1RST] = { true, SCU0_RESET_CTRL1, BIT(18) }, ++ [SCU0_RESET_PCIE1RSTOE] = { true, SCU0_RESET_CTRL1, BIT(19) }, ++ [SCU0_RESET_PCIE0RST] = { true, SCU0_RESET_CTRL1, BIT(20) }, ++ [SCU0_RESET_PCIE0RSTOE] = { true, SCU0_RESET_CTRL1, BIT(21) }, ++ [SCU0_RESET_JTAG] = { true, SCU0_RESET_CTRL1, BIT(22) }, ++ [SCU0_RESET_MCTP0] = { true, SCU0_RESET_CTRL1, BIT(23) }, ++ [SCU0_RESET_MCTP1] = { true, SCU0_RESET_CTRL1, BIT(24) }, ++ [SCU0_RESET_XDMA0] = { true, SCU0_RESET_CTRL1, BIT(25) }, ++ [SCU0_RESET_XDMA1] = { true, SCU0_RESET_CTRL1, BIT(26) }, ++ [SCU0_RESET_H2X1] = { true, SCU0_RESET_CTRL1, BIT(27) }, ++ [SCU0_RESET_DP] = { true, SCU0_RESET_CTRL1, BIT(28) }, ++ [SCU0_RESET_DP_MCU] = { true, SCU0_RESET_CTRL1, BIT(29) }, ++ [SCU0_RESET_SSP] = { true, SCU0_RESET_CTRL1, BIT(30) }, ++ [SCU0_RESET_H2X0] = { true, SCU0_RESET_CTRL1, BIT(31) }, ++ [SCU0_RESET_PORTA_VHUB] = { true, SCU0_RESET_CTRL2, BIT(0) }, ++ [SCU0_RESET_PORTA_PHY3] = { true, SCU0_RESET_CTRL2, BIT(1) }, ++ [SCU0_RESET_PORTA_XHCI] = { true, SCU0_RESET_CTRL2, BIT(2) }, ++ [SCU0_RESET_PORTB_VHUB] = { true, SCU0_RESET_CTRL2, BIT(3) }, ++ [SCU0_RESET_PORTB_PHY3] = { true, SCU0_RESET_CTRL2, BIT(4) }, ++ [SCU0_RESET_PORTB_XHCI] = { true, SCU0_RESET_CTRL2, BIT(5) }, ++ [SCU0_RESET_PORTA_VHUB_EHCI] = { true, SCU0_RESET_CTRL2, BIT(6) }, ++ [SCU0_RESET_PORTB_VHUB_EHCI] = { true, SCU0_RESET_CTRL2, BIT(7) }, ++ [SCU0_RESET_UHCI] = { true, SCU0_RESET_CTRL2, BIT(8) }, ++ [SCU0_RESET_TSP] = { true, SCU0_RESET_CTRL2, BIT(9) }, ++ [SCU0_RESET_E2M0] = { true, SCU0_RESET_CTRL2, BIT(10) }, ++ [SCU0_RESET_E2M1] = { true, SCU0_RESET_CTRL2, BIT(11) }, ++ [SCU0_RESET_VLINK] = { true, SCU0_RESET_CTRL2, BIT(12) }, ++}; + -+ return state; -+} ++static const struct ast2700_reset_signal ast2700_reset1_signals[] = { ++ [SCU1_RESET_LPC0] = { true, SCU1_RESET_CTRL1, BIT(0) }, ++ [SCU1_RESET_LPC1] = { true, SCU1_RESET_CTRL1, BIT(1) }, ++ [SCU1_RESET_MII] = { true, SCU1_RESET_CTRL1, BIT(2) }, ++ [SCU1_RESET_PECI] = { true, SCU1_RESET_CTRL1, BIT(3) }, ++ [SCU1_RESET_PWM] = { true, SCU1_RESET_CTRL1, BIT(4) }, ++ [SCU1_RESET_MAC0] = { true, SCU1_RESET_CTRL1, BIT(5) }, ++ [SCU1_RESET_MAC1] = { true, SCU1_RESET_CTRL1, BIT(6) }, ++ [SCU1_RESET_MAC2] = { true, SCU1_RESET_CTRL1, BIT(7) }, ++ [SCU1_RESET_ADC] = { true, SCU1_RESET_CTRL1, BIT(8) }, ++ [SCU1_RESET_SD] = { true, SCU1_RESET_CTRL1, BIT(9) }, ++ [SCU1_RESET_ESPI0] = { true, SCU1_RESET_CTRL1, BIT(10) }, ++ [SCU1_RESET_ESPI1] = { true, SCU1_RESET_CTRL1, BIT(11) }, ++ [SCU1_RESET_JTAG1] = { true, SCU1_RESET_CTRL1, BIT(12) }, ++ [SCU1_RESET_SPI0] = { true, SCU1_RESET_CTRL1, BIT(13) }, ++ [SCU1_RESET_SPI1] = { true, SCU1_RESET_CTRL1, BIT(14) }, ++ [SCU1_RESET_SPI2] = { true, SCU1_RESET_CTRL1, BIT(15) }, ++ [SCU1_RESET_I3C0] = { true, SCU1_RESET_CTRL1, BIT(16) }, ++ [SCU1_RESET_I3C1] = { true, SCU1_RESET_CTRL1, BIT(17) }, ++ [SCU1_RESET_I3C2] = { true, SCU1_RESET_CTRL1, BIT(18) }, ++ [SCU1_RESET_I3C3] = { true, SCU1_RESET_CTRL1, BIT(19) }, ++ [SCU1_RESET_I3C4] = { true, SCU1_RESET_CTRL1, BIT(20) }, ++ [SCU1_RESET_I3C5] = { true, SCU1_RESET_CTRL1, BIT(21) }, ++ [SCU1_RESET_I3C6] = { true, SCU1_RESET_CTRL1, BIT(22) }, ++ [SCU1_RESET_I3C7] = { true, SCU1_RESET_CTRL1, BIT(23) }, ++ [SCU1_RESET_I3C8] = { true, SCU1_RESET_CTRL1, BIT(24) }, ++ [SCU1_RESET_I3C9] = { true, SCU1_RESET_CTRL1, BIT(25) }, ++ [SCU1_RESET_I3C10] = { true, SCU1_RESET_CTRL1, BIT(26) }, ++ [SCU1_RESET_I3C11] = { true, SCU1_RESET_CTRL1, BIT(27) }, ++ [SCU1_RESET_I3C12] = { true, SCU1_RESET_CTRL1, BIT(28) }, ++ [SCU1_RESET_I3C13] = { true, SCU1_RESET_CTRL1, BIT(29) }, ++ [SCU1_RESET_I3C14] = { true, SCU1_RESET_CTRL1, BIT(30) }, ++ [SCU1_RESET_I3C15] = { true, SCU1_RESET_CTRL1, BIT(31) }, ++ [SCU1_RESET_MCU0] = { true, SCU1_RESET_CTRL2, BIT(0) }, ++ [SCU1_RESET_MCU1] = { true, SCU1_RESET_CTRL2, BIT(1) }, ++ [SCU1_RESET_H2A_SPI1] = { true, SCU1_RESET_CTRL2, BIT(2) }, ++ [SCU1_RESET_H2A_SPI2] = { true, SCU1_RESET_CTRL2, BIT(3) }, ++ [SCU1_RESET_UART0] = { true, SCU1_RESET_CTRL2, BIT(4) }, ++ [SCU1_RESET_UART1] = { true, SCU1_RESET_CTRL2, BIT(5) }, ++ [SCU1_RESET_UART2] = { true, SCU1_RESET_CTRL2, BIT(6) }, ++ [SCU1_RESET_UART3] = { true, SCU1_RESET_CTRL2, BIT(7) }, ++ [SCU1_RESET_I2C_FILTER] = { true, SCU1_RESET_CTRL2, BIT(8) }, ++ [SCU1_RESET_CALIPTRA] = { true, SCU1_RESET_CTRL2, BIT(9) }, ++ [SCU1_RESET_XDMA] = { true, SCU1_RESET_CTRL2, BIT(10) }, ++ [SCU1_RESET_FSI] = { true, SCU1_RESET_CTRL2, BIT(12) }, ++ [SCU1_RESET_CAN] = { true, SCU1_RESET_CTRL2, BIT(13) }, ++ [SCU1_RESET_MCTP] = { true, SCU1_RESET_CTRL2, BIT(14) }, ++ [SCU1_RESET_I2C] = { true, SCU1_RESET_CTRL2, BIT(15) }, ++ [SCU1_RESET_UART6] = { true, SCU1_RESET_CTRL2, BIT(16) }, ++ [SCU1_RESET_UART7] = { true, SCU1_RESET_CTRL2, BIT(17) }, ++ [SCU1_RESET_UART8] = { true, SCU1_RESET_CTRL2, BIT(18) }, ++ [SCU1_RESET_UART9] = { true, SCU1_RESET_CTRL2, BIT(19) }, ++ [SCU1_RESET_LTPI0] = { true, SCU1_RESET_CTRL2, BIT(20) }, ++ [SCU1_RESET_VGAL] = { true, SCU1_RESET_CTRL2, BIT(21) }, ++ [SCU1_RESET_LTPI1] = { true, SCU1_RESET_CTRL2, BIT(22) }, ++ [SCU1_RESET_ACE] = { true, SCU1_RESET_CTRL2, BIT(23) }, ++ [SCU1_RESET_E2M] = { true, SCU1_RESET_CTRL2, BIT(24) }, ++ [SCU1_RESET_UHCI] = { true, SCU1_RESET_CTRL2, BIT(25) }, ++ [SCU1_RESET_PORTC_USB2UART] = { true, SCU1_RESET_CTRL2, BIT(26) }, ++ [SCU1_RESET_PORTC_VHUB_EHCI] = { true, SCU1_RESET_CTRL2, BIT(27) }, ++ [SCU1_RESET_PORTD_USB2UART] = { true, SCU1_RESET_CTRL2, BIT(28) }, ++ [SCU1_RESET_PORTD_VHUB_EHCI] = { true, SCU1_RESET_CTRL2, BIT(29) }, ++ [SCU1_RESET_H2X] = { true, SCU1_RESET_CTRL2, BIT(30) }, ++ [SCU1_RESET_I3CDMA] = { true, SCU1_RESET_CTRL2, BIT(31) }, ++ [SCU1_RESET_PCIE2RST] = { false, SCU1_PCIE3_CTRL, BIT(0) }, ++}; + -+static void raise_h2b_interrupt(struct aspeed_mmbi_channel *chan) ++static inline struct aspeed_reset *to_aspeed_reset(struct reset_controller_dev *rcdev) +{ -+ if (!chan->bmc_int_en) -+ return; -+ -+ writeb(chan->bmc_int_value, chan->desc_vmem + chan->bmc_int_location); ++ return container_of(rcdev, struct aspeed_reset, rcdev); +} + -+static int mmbi_state_check(struct aspeed_mmbi_channel *chan) ++static int aspeed_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) +{ -+ 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); ++ struct aspeed_reset *rc = to_aspeed_reset(rcdev); ++ void __iomem *reg_offset = rc->base + rc->info->signal[id].offset; + -+ dev_dbg(dev, "Change state to RESET_ACKED to BMC"); -+ raise_h2b_interrupt(chan); -+ default: -+ break; ++ if (rc->info->signal[id].dedicated_clr) { ++ writel(rc->info->signal[id].bit, reg_offset); ++ } else { ++ guard(spinlock_irqsave)(&rc->lock); ++ writel(readl(reg_offset) & ~rc->info->signal[id].bit, reg_offset); + } + + return 0; +} + -+static int mmbi_bmc_up_check(struct aspeed_mmbi_channel *chan) ++static int aspeed_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) +{ -+ u64 __timeout_us = 1000; -+ ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); -+ -+ for (;;) { -+ enum mmbi_state current_state = mmbi_get_state(chan); ++ struct aspeed_reset *rc = to_aspeed_reset(rcdev); ++ void __iomem *reg_offset = rc->base + rc->info->signal[id].offset; + -+ if (current_state == INIT_COMPLETED) -+ break; -+ if (__timeout_us && ktime_compare(ktime_get(), __timeout) > 0) -+ return -EAGAIN; ++ if (rc->info->signal[id].dedicated_clr) { ++ writel(rc->info->signal[id].bit, reg_offset + 0x04); ++ } else { ++ guard(spinlock_irqsave)(&rc->lock); ++ writel(readl(reg_offset) | rc->info->signal[id].bit, reg_offset); + } + + return 0; +} + -+static void update_host_rws(struct aspeed_mmbi_channel *chan, unsigned int w_len, -+ unsigned int r_len) ++static int aspeed_reset_status(struct reset_controller_dev *rcdev, unsigned long id) +{ -+ struct device *dev = chan->dev; -+ struct host_rws hrws; -+ u32 h2b_wp, b2h_rp; ++ struct aspeed_reset *rc = to_aspeed_reset(rcdev); ++ void __iomem *reg_offset = rc->base + rc->info->signal[id].offset; + -+ h2b_wp = GET_H2B_WRITE_POINTER(chan); -+ b2h_rp = GET_B2H_READ_POINTER(chan); ++ return (readl(reg_offset) & rc->info->signal[id].bit) ? 1 : 0; ++} + -+ dev_dbg(dev, "MMBI HRWS - b2h_rp: 0x%0x, h2b_wp: 0x%0x\n", b2h_rp, h2b_wp); ++static const struct reset_control_ops aspeed_reset_ops = { ++ .assert = aspeed_reset_assert, ++ .deassert = aspeed_reset_deassert, ++ .status = aspeed_reset_status, ++}; + -+ /* 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; ++static int aspeed_reset_probe(struct auxiliary_device *adev, ++ const struct auxiliary_device_id *id) ++{ ++ struct aspeed_reset *reset; ++ struct device *dev = &adev->dev; + -+ /* 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; ++ reset = devm_kzalloc(dev, sizeof(*reset), GFP_KERNEL); ++ if (!reset) ++ return -ENOMEM; + -+ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); ++ spin_lock_init(&reset->lock); + -+ 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); ++ reset->info = (struct aspeed_reset_info *)id->driver_data; ++ reset->rcdev.owner = THIS_MODULE; ++ reset->rcdev.nr_resets = reset->info->nr_resets; ++ reset->rcdev.ops = &aspeed_reset_ops; ++ reset->rcdev.of_node = dev->parent->of_node; ++ reset->rcdev.dev = dev; ++ reset->rcdev.of_reset_n_cells = 1; ++ reset->base = (void __iomem *)adev->dev.platform_data; + -+ if (w_len != 0) -+ raise_h2b_interrupt(chan); ++ dev_set_drvdata(dev, reset); ++ ++ return devm_reset_controller_register(dev, &reset->rcdev); +} + -+static int get_mmbi_header(struct aspeed_mmbi_channel *chan, u32 *data_length, u8 *type, -+ u32 *unread_data_len, u8 *padding) ++static void aspeed_reset_unregister_adev(void *_adev) +{ -+ u32 h2b_wp, h2b_rp, b2h_wp, b2h_rp; -+ struct mmbi_header header; ++ struct auxiliary_device *adev = _adev; + -+ 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); ++ auxiliary_device_delete(adev); ++ auxiliary_device_uninit(adev); ++} + -+ if (b2h_wp >= b2h_rp) -+ *unread_data_len = b2h_wp - b2h_rp; -+ else -+ *unread_data_len = chan->b2h_cb_size - b2h_rp + b2h_wp; ++static void aspeed_reset_adev_release(struct device *dev) ++{ ++ struct auxiliary_device *adev = to_auxiliary_dev(dev); + -+ 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; -+ } ++ kfree(adev); ++} + -+ dev_dbg(chan->dev, "READ MMBI header from: %p\n", chan->b2h_cb_vmem + b2h_rp); ++int aspeed_reset_controller_register(struct device *clk_dev, void __iomem *base, ++ const char *adev_name) ++{ ++ struct auxiliary_device *adev; ++ int ret; + -+ /* 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; ++ adev = kzalloc(sizeof(*adev), GFP_KERNEL); ++ if (!adev) ++ return -ENOMEM; + -+ 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); ++ adev->name = adev_name; ++ adev->dev.parent = clk_dev; ++ adev->dev.release = aspeed_reset_adev_release; ++ adev->id = 666u; ++ ++ ret = auxiliary_device_init(adev); ++ if (ret) { ++ kfree(adev); ++ return ret; + } + -+ *data_length = (header.pkt_len << 2) - sizeof(header) - header.pkt_pad; -+ *padding = header.pkt_pad; -+ *type = header.pkt_type; ++ ret = auxiliary_device_add(adev); ++ if (ret) { ++ auxiliary_device_uninit(adev); ++ return ret; ++ } + -+ return 0; ++ adev->dev.platform_data = (__force void *)base; ++ ++ return devm_add_action_or_reset(clk_dev, aspeed_reset_unregister_adev, adev); +} ++EXPORT_SYMBOL_GPL(aspeed_reset_controller_register); + -+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; ++static const struct aspeed_reset_info ast2700_reset0_info = { ++ .nr_resets = ARRAY_SIZE(ast2700_reset0_signals), ++ .signal = ast2700_reset0_signals, ++}; + -+ /* 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; -+ } ++static const struct aspeed_reset_info ast2700_reset1_info = { ++ .nr_resets = ARRAY_SIZE(ast2700_reset1_signals), ++ .signal = ast2700_reset1_signals, ++}; + -+ get_h2b_avail_buf_len(chan, &avail_buf_len); ++static const struct auxiliary_device_id aspeed_reset_ids[] = { ++ { .name = "reset_aspeed.reset0", .driver_data = (kernel_ulong_t)&ast2700_reset0_info }, ++ { .name = "reset_aspeed.reset1", .driver_data = (kernel_ulong_t)&ast2700_reset1_info }, ++ { } ++}; ++MODULE_DEVICE_TABLE(auxiliary, aspeed_reset_ids); + -+ dev_dbg(dev, "H2B buffer empty space: %zd\n", avail_buf_len); ++static struct auxiliary_driver aspeed_reset_driver = { ++ .probe = aspeed_reset_probe, ++ .id_table = aspeed_reset_ids, ++}; + -+ /* Header size */ -+ total_len = len + 4; ++static int __init rest_aspeed_init(void) ++{ ++ return auxiliary_driver_register(&aspeed_reset_driver); ++} ++subsys_initcall(rest_aspeed_init); + -+ padding = total_len & 0x3; -+ if (padding) -+ padding = 4 - padding; -+ total_len += padding; ++MODULE_AUTHOR("Ryan Chen "); ++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 +@@ -10,14 +10,64 @@ + struct aspeed_rtc { + struct rtc_device *rtc_dev; + void __iomem *base; ++ spinlock_t irq_lock; /* interrupt enable register lock */ ++ struct mutex write_mutex; /* serialize registers write */ + }; + + #define RTC_TIME 0x00 + #define RTC_YEAR 0x04 ++#define RTC_ALARM 0x08 + #define RTC_CTRL 0x10 ++#define RTC_ALARM_STATUS 0x14 + +-#define RTC_UNLOCK BIT(1) +-#define RTC_ENABLE BIT(0) ++#define RTC_ENABLE BIT(0) ++#define RTC_UNLOCK BIT(1) ++#define RTC_ALARM_MODE BIT(2) ++#define RTC_ALARM_SEC_ENABLE BIT(3) ++#define RTC_ALARM_MIN_ENABLE BIT(4) ++#define RTC_ALARM_HOUR_ENABLE BIT(5) ++#define RTC_ALARM_MDAY_ENABLE BIT(6) + -+ /* 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; ++#define RTC_ALARM_SEC_CB_STATUS BIT(0) ++#define RTC_ALARM_MIN_STATUS BIT(1) ++#define RTC_ALARM_HOUR_STATUS BIT(2) ++#define RTC_ALARM_MDAY_STATUS BIT(3) + -+ /* Fill multi-protocol header */ -+ header.pkt_type = type; -+ header.pkt_len = total_len >> 2; -+ header.pkt_pad = padding; ++/* ++ * enable a rtc interrupt ++ */ ++static void aspeed_rtc_int_enable(struct aspeed_rtc *rtc, u32 intr) ++{ ++ unsigned long flags; + -+ wt_offset = GET_H2B_WRITE_POINTER(chan); -+ end_offset = chan->h2b_cb_size; ++ spin_lock_irqsave(&rtc->irq_lock, flags); ++ writel(readl(rtc->base + RTC_CTRL) | intr, rtc->base + RTC_CTRL); ++ spin_unlock_irqrestore(&rtc->irq_lock, flags); ++} + -+ /* 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); -+ } ++/* ++ * disable a rtc interrupt ++ */ ++static void aspeed_rtc_int_disable(struct aspeed_rtc *rtc, u32 intr) ++{ ++ unsigned long flags; + -+ /* 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; -+ } ++ spin_lock_irqsave(&rtc->irq_lock, flags); ++ writel(readl(rtc->base + RTC_CTRL) & ~intr, rtc->base + RTC_CTRL); ++ spin_unlock_irqrestore(&rtc->irq_lock, flags); ++} + -+ update_host_rws(chan, total_len, 0); ++/* ++ * clean a rtc interrupt status ++ */ ++static void aspeed_rtc_clean_alarm(struct aspeed_rtc *rtc) ++{ ++ unsigned long flags; + -+ return 0; ++ spin_lock_irqsave(&rtc->irq_lock, flags); ++ writel(readl(rtc->base + RTC_ALARM_STATUS), rtc->base + RTC_ALARM_STATUS); ++ spin_unlock_irqrestore(&rtc->irq_lock, flags); +} + + static int aspeed_rtc_read_time(struct device *dev, struct rtc_time *tm) + { +@@ -45,7 +95,7 @@ + tm->tm_mon = ((reg2 >> 0) & 0x0f) - 1; + tm->tm_year = year + (cent * 100) - 1900; + +- dev_dbg(dev, "%s %ptR", __func__, tm); ++ dev_dbg(dev, "%s %ptR\n", __func__, tm); + + return 0; + } +@@ -56,6 +106,8 @@ + u32 reg1, reg2, ctrl; + int year, cent; + ++ dev_dbg(dev, "%s %ptR\n", __func__, tm); + -+static void aspeed_mmbi_read(struct aspeed_mmbi_channel *chan, char *buffer, size_t len, u8 padding) + cent = (tm->tm_year + 1900) / 100; + year = tm->tm_year % 100; + +@@ -77,40 +129,211 @@ + return 0; + } + ++static int aspeed_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ -+ struct device *dev = chan->dev; -+ ssize_t rd_offset; -+ u32 b2h_rp; ++ struct aspeed_rtc *rtc = dev_get_drvdata(dev); ++ unsigned int alarm_enable; + -+ 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; ++ dev_dbg(dev, "%s, enabled:%x\n", __func__, enabled); + -+ /* 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); ++ alarm_enable = RTC_ALARM_MODE | RTC_ALARM_SEC_ENABLE | RTC_ALARM_MIN_ENABLE | ++ RTC_ALARM_HOUR_ENABLE | RTC_ALARM_MDAY_ENABLE; ++ if (enabled) ++ aspeed_rtc_int_enable(rtc, alarm_enable); ++ else ++ aspeed_rtc_int_disable(rtc, alarm_enable); + -+ 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; ++ return 0; ++} + -+ 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); ++static int aspeed_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) ++{ ++ struct aspeed_rtc *rtc = dev_get_drvdata(dev); ++ u32 reg1, reg2; ++ unsigned int alarm_enable; ++ unsigned int alarm_status; + -+ rd_offset = 0; -+ memcpy_fromio(buffer + chunk_len, chan->b2h_cb_vmem + rd_offset, -+ len - chunk_len); ++ if (!(readl(rtc->base + RTC_CTRL) & RTC_ENABLE)) { ++ dev_dbg(dev, "%s failing as rtc disabled\n", __func__); ++ return -EINVAL; + } + -+ update_host_rws(chan, 0, len + sizeof(struct mmbi_header) + padding); -+} ++ do { ++ reg2 = readl(rtc->base + RTC_YEAR); ++ reg1 = readl(rtc->base + RTC_TIME); ++ } while (reg1 != readl(rtc->base + RTC_TIME)); + -+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; ++ /* read alarm value */ ++ alarm->time.tm_mday = (reg1 >> 24) & 0x1f; ++ alarm->time.tm_hour = (reg1 >> 16) & 0x1f; ++ alarm->time.tm_min = (reg1 >> 8) & 0x3f; ++ alarm->time.tm_sec = (reg1 >> 0) & 0x3f; + -+ if (get_mmbi_header(chan, &req_data_len, &type, &unread_data_len, &padding) != 0) -+ return; ++ dev_dbg(dev, "%s %ptR\n", __func__, &alarm->time); + -+ dev_dbg(chan->dev, "%s: Length: 0x%0x, Protocol Type: %d, Unread data: %d\n", __func__, -+ req_data_len, type, unread_data_len); ++ alarm_enable = RTC_ALARM_SEC_ENABLE | RTC_ALARM_MIN_ENABLE | ++ RTC_ALARM_HOUR_ENABLE | RTC_ALARM_MDAY_ENABLE; ++ alarm_status = RTC_ALARM_SEC_CB_STATUS | RTC_ALARM_MIN_STATUS | ++ RTC_ALARM_HOUR_STATUS | RTC_ALARM_MDAY_STATUS; + -+ ndev = chan->ndev; ++ /* don't allow the ALARM read to mess up ALARM_STATUS */ ++ mutex_lock(&rtc->write_mutex); + -+ 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; -+ } ++ /* alarm is enabled if the interrupt is enabled */ ++ if (readl(rtc->base + RTC_CTRL) & alarm_enable) ++ alarm->enabled = true; ++ else ++ alarm->enabled = false; + -+ 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); ++ /* alarm interrupt asserted or not */ ++ if (readl(rtc->base + RTC_ALARM_STATUS) & alarm_status) ++ alarm->pending = true; ++ else ++ alarm->pending = false; + -+ cb = __mctp_cb(skb); -+ cb->halen = 0; ++ mutex_unlock(&rtc->write_mutex); + -+ 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++; -+ } ++ return 0; +} + -+static netdev_tx_t mctp_mmbi_tx(struct sk_buff *skb, struct net_device *ndev) ++static int aspeed_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ -+ 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; -+ } ++ struct aspeed_rtc *rtc = dev_get_drvdata(dev); ++ unsigned int alarm_enable; ++ u32 reg; + -+ ret = aspeed_mmbi_write(&mctp->mmbi->chan, skb->data, skb->len, MMBI_PROTOCOL_MCTP); -+ if (ret) { -+ netif_stop_queue(ndev); -+ return NETDEV_TX_BUSY; ++ if (!(readl(rtc->base + RTC_CTRL) & RTC_ENABLE)) { ++ dev_dbg(dev, "%s failing as rtc disabled\n", __func__); ++ return -EINVAL; + } + -+ 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; ++ dev_dbg(dev, "%s %ptR\n", __func__, &alarm->time); + -+ 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; -+} ++ alarm_enable = RTC_ALARM_MODE | RTC_ALARM_SEC_ENABLE | RTC_ALARM_MIN_ENABLE | ++ RTC_ALARM_HOUR_ENABLE | RTC_ALARM_MDAY_ENABLE; + -+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; ++ /* don't allow the ALARM read to mess up ALARM_STATUS */ ++ mutex_lock(&rtc->write_mutex); + -+ 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; ++ /* write the new alarm time */ ++ reg = (alarm->time.tm_mday << 24) | (alarm->time.tm_hour << 16) | ++ (alarm->time.tm_min << 8) | alarm->time.tm_sec; ++ writel(reg, rtc->base + RTC_ALARM); + -+ chan->ndev = ndev; ++ /* alarm is enabled if the interrupt is enabled */ ++ if (alarm->enabled) ++ aspeed_rtc_int_enable(rtc, alarm_enable); ++ else ++ aspeed_rtc_int_disable(rtc, alarm_enable); + -+ ret = register_netdev(ndev); -+ if (ret) -+ goto free_netdev; ++ mutex_unlock(&rtc->write_mutex); + + return 0; ++} + -+free_netdev: -+ free_netdev(ndev); + static const struct rtc_class_ops aspeed_rtc_ops = { +- .read_time = aspeed_rtc_read_time, +- .set_time = aspeed_rtc_set_time, ++ .read_time = aspeed_rtc_read_time, ++ .set_time = aspeed_rtc_set_time, ++ .alarm_irq_enable = aspeed_rtc_alarm_irq_enable, ++ .read_alarm = aspeed_rtc_read_alarm, ++ .set_alarm = aspeed_rtc_set_alarm, + }; + ++static irqreturn_t aspeed_rtc_irq(int irq, void *dev_id) ++{ ++ struct aspeed_rtc *rtc = dev_id; ++ unsigned int alarm_enable; + -+ return ret; -+} ++ alarm_enable = RTC_ALARM_MODE | RTC_ALARM_SEC_ENABLE | RTC_ALARM_MIN_ENABLE | ++ RTC_ALARM_HOUR_ENABLE | RTC_ALARM_MDAY_ENABLE; ++ aspeed_rtc_int_disable(rtc, alarm_enable); ++ aspeed_rtc_clean_alarm(rtc); + -+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); ++ return IRQ_HANDLED; +} + -+static int aspeed_pci_bmc_dev_mmap(struct file *file, struct vm_area_struct *vma) -+{ -+ struct aspeed_pci_bmc_dev *pci_bmc_dev = file_aspeed_bmc_device(file); -+ unsigned long vsize = vma->vm_end - vma->vm_start; -+ pgprot_t prot = vma->vm_page_prot; + static int aspeed_rtc_probe(struct platform_device *pdev) + { + struct aspeed_rtc *rtc; ++ unsigned int irq; ++ int rc; ++ u32 ctrl; + + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; + + rtc->base = devm_platform_ioremap_resource(pdev, 0); +- if (IS_ERR(rtc->base)) ++ if (IS_ERR(rtc->base)) { ++ dev_err(&pdev->dev, "cannot ioremap resource for rtc\n"); + return PTR_ERR(rtc->base); ++ } + + rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(rtc->rtc_dev)) + return PTR_ERR(rtc->rtc_dev); + ++ spin_lock_init(&rtc->irq_lock); ++ mutex_init(&rtc->write_mutex); + -+ if (vma->vm_pgoff + vsize > pci_bmc_dev->mem_bar_base + 0x100000) -+ return -EINVAL; ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) ++ return irq; + -+ prot = pgprot_noncached(prot); ++ rc = devm_request_irq(&pdev->dev, irq, aspeed_rtc_irq, ++ 0, pdev->name, rtc); ++ if (rc) { ++ dev_err(&pdev->dev, "interrupt number %d is not available.\n", irq); ++ goto err; ++ } + -+ if (remap_pfn_range(vma, vma->vm_start, -+ (pci_bmc_dev->mem_bar_base >> PAGE_SHIFT) + vma->vm_pgoff, -+ vsize, prot)) -+ return -EAGAIN; + platform_set_drvdata(pdev, rtc); + ++ device_init_wakeup(&pdev->dev, true); + -+ return 0; -+} + rtc->rtc_dev->ops = &aspeed_rtc_ops; + rtc->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_1900; + rtc->rtc_dev->range_max = 38814989399LL; /* 3199-12-31 23:59:59 */ + +- return devm_rtc_register_device(rtc->rtc_dev); ++ /* ++ * In devm_rtc_register_device, ++ * rtc_hctosys read time from RTC to check hardware status. ++ * In rtc_read_time, run aspeed_rtc_read_time and check the rtc_time. ++ * As a result, need to enable and initialize RTC time. ++ * ++ * 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); + -+static const struct file_operations aspeed_pci_bmc_dev_fops = { -+ .owner = THIS_MODULE, -+ .mmap = aspeed_pci_bmc_dev_mmap, -+}; ++ /* ++ * 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); + -+static ssize_t aspeed_queue_rx(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, -+ char *buf, loff_t off, size_t count) -+{ -+ struct aspeed_queue_message *queue = attr->private; -+ struct aspeed_pci_bmc_dev *pci_bmc_device = queue->pci_bmc_device; -+ int index = queue->index; -+ u32 *data = (u32 *)buf; -+ int ret; ++ /* Re-lock and ensure enable is set now that a time is programmed */ ++ writel(ctrl | RTC_ENABLE, rtc->base + RTC_CTRL); + -+ ret = wait_event_interruptible(queue->rx_wait, -+ !(readl(pci_bmc_device->msg_bar_reg + PCI_BMC_BMC2HOST_STS) & -+ ((index == QUEUE1) ? BMC2HOST_Q1_EMPTY : BMC2HOST_Q2_EMPTY))); -+ if (ret) -+ return -EINTR; ++ rc = devm_rtc_register_device(rtc->rtc_dev); ++ if (rc) { ++ dev_err(&pdev->dev, "can't register rtc device\n"); ++ goto err; ++ } + -+ data[0] = readl(pci_bmc_device->msg_bar_reg + -+ ((index == QUEUE1) ? PCI_BMC_BMC2HOST_Q1 : PCI_BMC_BMC2HOST_Q2)); ++ return 0; + -+ writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, -+ pci_bmc_device->msg_bar_reg + PCI_BMC_HOST2BMC_STS); ++err: ++ return rc; + } + + static const struct of_device_id aspeed_rtc_match[] = { + { .compatible = "aspeed,ast2400-rtc", }, + { .compatible = "aspeed,ast2500-rtc", }, + { .compatible = "aspeed,ast2600-rtc", }, ++ { .compatible = "aspeed,ast2700-rtc", }, + {} + }; + 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 +@@ -4,6 +4,12 @@ + + menu "ASPEED SoC drivers" + ++config ASPEED_BMC_DEV ++ tristate "ASPEED BMC Device" + -+ return sizeof(u32); -+} ++config ASPEED_HOST_BMC_DEV ++ tristate "ASPEED Host BMC Device" + -+static ssize_t aspeed_queue_tx(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, -+ char *buf, loff_t off, size_t count) -+{ -+ struct aspeed_queue_message *queue = attr->private; -+ struct aspeed_pci_bmc_dev *pci_bmc_device = queue->pci_bmc_device; -+ int index = queue->index; -+ u32 tx_buff; -+ int ret; + config ASPEED_LPC_CTRL + tristate "ASPEED LPC firmware cycle control" + select REGMAP +@@ -24,6 +30,13 @@ + allows the BMC to listen on and save the data written by + the host to an arbitrary LPC I/O port. + ++config ASPEED_SSP ++ tristate "ASPEED SSP loader" ++ default n ++ help ++ Driver for loading secondary-service-processor binary + -+ if (count != sizeof(u32)) -+ return -EINVAL; + -+ ret = wait_event_interruptible(queue->tx_wait, -+ !(readl(pci_bmc_device->msg_bar_reg + PCI_BMC_HOST2BMC_STS) & -+ ((index == QUEUE1) ? HOST2BMC_Q1_FULL : HOST2BMC_Q2_FULL))); -+ if (ret) -+ return -EINTR; + config ASPEED_UART_ROUTING + tristate "ASPEED uart routing control" + select REGMAP +@@ -34,6 +47,16 @@ + users to perform runtime configuration of the RX muxes among + the UART controllers and I/O pins. + ++config ASPEED_LPC_MAILBOX ++ tristate "ASPEED LPC mailbox support" ++ select REGMAP ++ select MFD_SYSCON ++ default ARCH_ASPEED ++ help ++ Provides a driver to control the LPC mailbox which possesses ++ up to 32 data registers for the communication between the Host ++ and the BMC over LPC. + -+ memcpy(&tx_buff, buf, 4); -+ writel(tx_buff, pci_bmc_device->msg_bar_reg + -+ ((index == QUEUE1) ? PCI_BMC_HOST2BMC_Q1 : PCI_BMC_HOST2BMC_Q2)); -+ //trigger to host -+ writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, -+ pci_bmc_device->msg_bar_reg + PCI_BMC_HOST2BMC_STS); + config ASPEED_P2A_CTRL + tristate "ASPEED P2A (VGA MMIO to BMC) bridge control" + select REGMAP +@@ -52,6 +75,134 @@ + 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). + -+ return sizeof(u32); -+} ++config ASPEED_XDMA ++ tristate "ASPEED XDMA Engine Driver" ++ select REGMAP ++ select MFD_SYSCON ++ depends on HAS_DMA ++ help ++ Enables support for the XDMA Engine found on the ASPEED BMC ++ SoCs. The XDMA engine can perform PCIe DMA operations between the BMC ++ and a host processor. The driver provides ioctl() interface to reset ++ and initialize engine. + -+static irqreturn_t aspeed_pci_host_bmc_device_interrupt(int irq, void *dev_id) -+{ -+ struct aspeed_pci_bmc_dev *pci_bmc_device = dev_id; -+ u32 bmc2host_q_sts = readl(pci_bmc_device->msg_bar_reg + PCI_BMC_BMC2HOST_STS); ++config ASPEED_LPC_PCC ++ tristate "Aspeed Post Code Capture support" ++ depends on ARCH_ASPEED && REGMAP && MFD_SYSCON ++ help ++ Provides a driver to control the LPC PCC interface, ++ allowing the BMC to snoop data bytes written by the ++ the host to an arbitrary LPC I/O port. + -+ if (bmc2host_q_sts & BMC2HOST_INT_STS_DOORBELL) -+ writel(BMC2HOST_INT_STS_DOORBELL, -+ pci_bmc_device->msg_bar_reg + PCI_BMC_BMC2HOST_STS); ++config ASPEED_UDMA ++ tristate "Aspeed UDMA Engine Driver" ++ depends on ARCH_ASPEED && REGMAP && MFD_SYSCON && HAS_DMA ++ help ++ Enable support for the Aspeed UDMA Engine found on the Aspeed AST2XXX ++ SOCs. The UDMA engine can perform UART DMA operations between the memory ++ buffer and the UART/VUART devices. + -+ if (bmc2host_q_sts & BMC2HOST_ENABLE_INTB) -+ writel(BMC2HOST_ENABLE_INTB, pci_bmc_device->msg_bar_reg + PCI_BMC_BMC2HOST_STS); ++config ASPEED_MBOX ++ bool "Enable support for the ASPEED MBOX driver" ++ depends on ARCH_ASPEED ++ help ++ Enable support for the ASPEED MBOX driver. This driver ++ provides a mailbox client to the ASPEED BMC SoC IPC. + -+ if (bmc2host_q_sts & BMC2HOST_Q1_FULL) -+ dev_info(pci_bmc_device->dev, "Q1 Full\n"); ++config ASPEED_MCTP ++ tristate "Aspeed MCTP Controller support" ++ depends on REGMAP && MFD_SYSCON ++ help ++ Enable support for Aspeed MCTP Controller. ++ The MCTP controller allows the BMC to communicate with devices on ++ the host PCIe network. + -+ if (bmc2host_q_sts & BMC2HOST_Q2_FULL) -+ dev_info(pci_bmc_device->dev, "Q2 Full\n"); ++config ASPEED_DISP_INTF ++ bool "ASPEED Display Interface driver" ++ select REGMAP ++ select MFD_SYSCON ++ default ARCH_ASPEED ++ help ++ Say yes to support control the display interface of ASPEED BMC. + -+ //check q1 -+ if (!(readl(pci_bmc_device->msg_bar_reg + PCI_BMC_HOST2BMC_STS) & HOST2BMC_Q1_FULL)) -+ wake_up_interruptible(&pci_bmc_device->queue[QUEUE1].tx_wait); ++config ASPEED_UDMA ++ tristate "Aspeed UDMA Engine Driver" ++ depends on ARCH_ASPEED && REGMAP && MFD_SYSCON && HAS_DMA ++ help ++ Enable support for the Aspeed UDMA Engine found on the Aspeed AST2XXX ++ SOCs. The UDMA engine can perform UART DMA operations between the memory ++ buffer and the UART/VUART devices. + -+ if (!(readl(pci_bmc_device->msg_bar_reg + PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q1_EMPTY)) -+ wake_up_interruptible(&pci_bmc_device->queue[QUEUE1].rx_wait); -+ //chech q2 -+ if (!(readl(pci_bmc_device->msg_bar_reg + PCI_BMC_HOST2BMC_STS) & HOST2BMC_Q2_FULL)) -+ wake_up_interruptible(&pci_bmc_device->queue[QUEUE2].tx_wait); ++config ASPEED_PCIE_MMBI ++ tristate "ASPEED PCIE MMBI" + -+ if (!(readl(pci_bmc_device->msg_bar_reg + PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q2_EMPTY)) -+ wake_up_interruptible(&pci_bmc_device->queue[QUEUE2].rx_wait); ++config ASPEED_ESPI ++ tristate "ASPEED eSPI slave driver" ++ select AST2500_ESPI if MACH_ASPEED_G5 ++ select AST2600_ESPI if MACH_ASPEED_G6 ++ default n + -+ return IRQ_HANDLED; -+} ++config AST2500_ESPI ++ tristate ++ depends on ASPEED_ESPI ++ help ++ Enable driver support for Aspeed AST2500 eSPI engine. + -+static irqreturn_t aspeed_pci_host_mbox_interrupt(int irq, void *dev_id) -+{ -+ struct aspeed_pci_bmc_dev *pci_bmc_device = dev_id; -+ u32 isr = readl(pci_bmc_device->sio_mbox_reg + 0x94); ++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. + -+ if (isr & BIT(7)) -+ writel(BIT(7), pci_bmc_device->sio_mbox_reg + 0x94); ++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. + -+ return IRQ_HANDLED; -+} ++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 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; ++config ASPEED_OTP ++ tristate ++ help ++ Enable driver support for Aspeed OTP driver. Each bit in One ++ Time Prgrammable (OTP) memory is capable to be programmed once. ++ The OTP driver performs basic read/program operations of ++ OTP memory. + -+ for (i = 0; i < weight; i++) { -+ if (get_mmbi_header(chan, &req_data_len, &type, &unread_data_len, &padding) != 0) -+ return; ++config AST2600_OTP ++ tristate "AST2600 OTP Driver" ++ select ASPEED_OTP ++ depends on ARCH_ASPEED ++ help ++ Enable driver support for Aspeed AST2600 OTP driver. + -+ dev_dbg(chan->dev, "%s: Length: 0x%0x, Protocol Type: %d\n", -+ __func__, req_data_len, type); ++config AST2700_OTP ++ tristate "AST2700 OTP Driver" ++ select ASPEED_OTP ++ depends on ARCH_ASPEED ++ help ++ Enable driver support for Aspeed AST2700 OTP driver. + -+ 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); ++source "drivers/soc/aspeed/rvas/Kconfig" + -+ raise_h2b_interrupt(chan); -+ } + 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 @@ + # 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 + obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o + obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o ++obj-$(CONFIG_ASPEED_LPC_MAILBOX) += aspeed-lpc-mbox.o ++obj-$(CONFIG_ASPEED_LPC_PCC) += aspeed-lpc-pcc.o ++obj-$(CONFIG_ASPEED_UDMA) += aspeed-udma.o + obj-$(CONFIG_ASPEED_UART_ROUTING) += aspeed-uart-routing.o ++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 ++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 +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 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++// Copyright (C) ASPEED Technology Inc. + -+ if (get_mmbi_header(chan, &req_data_len, &type, &unread_data_len, &padding) != 0) -+ queue_work(system_unbound_wq, &chan->work); -+} ++#include ++#include ++#include ++#include + -+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; ++#include ++#include ++#include ++#include ++#include ++#include + -+ 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); -+ } -+ } ++#include ++#include + -+ if (mmbi_state_check(chan)) -+ return IRQ_HANDLED; ++#include ++#include ++#include ++#include ++#include + -+ queue_work(system_unbound_wq, &chan->work); ++#define SCU_TRIGGER_MSI + -+ return IRQ_HANDLED; -+} ++/* AST2600 SCU */ ++#define ASPEED_SCU04 0x04 ++#define AST2600A3_SCU04 0x05030303 ++#define ASPEED_SCUC20 0xC20 ++#define ASPEED_SCUC24 0xC24 ++#define MSI_ROUTING_MASK GENMASK(11, 10) ++#define PCIDEV1_INTX_MSI_HOST2BMC_EN BIT(18) ++#define MSI_ROUTING_PCIe2LPC_PCIDEV0 (0x1 << 10) ++#define MSI_ROUTING_PCIe2LPC_PCIDEV1 (0x2 << 10) ++/* AST2700 SCU */ ++#define SCU0_REVISION_ID 0x0 ++#define REVISION_ID GENMASK(23, 16) ++#define SCU0_PCIE_CONF_CTRL 0x970 ++/* Host2BMC */ ++#define ASPEED_BMC_MEM_BAR 0xF10 ++#define PCIE2PCI_MEM_BAR_ENABLE BIT(1) ++#define HOST2BMC_MEM_BAR_ENABLE BIT(0) ++#define ASPEED_BMC_MEM_BAR_REMAP 0xF18 + -+static void aspeed_pci_setup_irq_resource(struct pci_dev *pdev) -+{ -+ struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); ++#define ASPEED_BMC_SHADOW_CTRL 0xF50 ++#define READ_ONLY_MASK BIT(31) ++#define MASK_BAR1 BIT(2) ++#define MASK_BAR0 BIT(1) ++#define SHADOW_CFG BIT(0) + -+ /* 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; -+ } -+ } else { -+ pci_bmc_dev->msi_idx_table = ast2600_msi_idx_table; -+ } ++#define ASPEED_BMC_HOST2BMC_Q1 0xA000 ++#define ASPEED_BMC_HOST2BMC_Q2 0xA010 ++#define ASPEED_BMC_BMC2HOST_Q1 0xA020 ++#define ASPEED_BMC_BMC2HOST_Q2 0xA030 ++#define ASPEED_BMC_BMC2HOST_STS 0xA040 ++#define BMC2HOST_INT_STS_DOORBELL BIT(31) ++#define BMC2HOST_ENABLE_INTB BIT(30) ++#define BMC2HOST_Q1_FULL BIT(27) ++#define BMC2HOST_Q1_EMPTY BIT(26) ++#define BMC2HOST_Q2_FULL BIT(25) ++#define BMC2HOST_Q2_EMPTY BIT(24) ++#define BMC2HOST_Q1_FULL_UNMASK BIT(23) ++#define BMC2HOST_Q1_EMPTY_UNMASK BIT(22) ++#define BMC2HOST_Q2_FULL_UNMASK BIT(21) ++#define BMC2HOST_Q2_EMPTY_UNMASK BIT(20) + -+ if (pci_alloc_irq_vectors(pdev, 1, BMC_MULTI_MSI, PCI_IRQ_INTX | PCI_IRQ_MSI) <= 1) -+ /* Set all msi index to the first vector */ -+ memset(pci_bmc_dev->msi_idx_table, 0, sizeof(int) * MAX_MSI_NUM); -+} ++#define ASPEED_BMC_HOST2BMC_STS 0xA044 ++#define HOST2BMC_INT_STS_DOORBELL BIT(31) ++#define HOST2BMC_ENABLE_INTB BIT(30) ++#define HOST2BMC_Q1_FULL BIT(27) ++#define HOST2BMC_Q1_EMPTY BIT(26) ++#define HOST2BMC_Q2_FULL BIT(25) ++#define HOST2BMC_Q2_EMPTY BIT(24) ++#define HOST2BMC_Q1_FULL_UNMASK BIT(23) ++#define HOST2BMC_Q1_EMPTY_UNMASK BIT(22) ++#define HOST2BMC_Q2_FULL_UNMASK BIT(21) ++#define HOST2BMC_Q2_EMPTY_UNMASK BIT(20) + -+static int aspeed_pci_bmc_device_setup_queue(struct pci_dev *pdev) -+{ -+ struct aspeed_pci_bmc_dev *pci_bmc_device = pci_get_drvdata(pdev); -+ struct device *dev = &pdev->dev; -+ int ret, i; ++#define ASPEED_SCU_PCIE_CONF_CTRL 0xC20 ++#define SCU_PCIE_CONF_BMC_DEV_EN BIT(8) ++#define SCU_PCIE_CONF_BMC_DEV_EN_MMIO BIT(9) ++#define SCU_PCIE_CONF_BMC_DEV_EN_MSI BIT(11) ++#define SCU_PCIE_CONF_BMC_DEV_EN_IRQ BIT(13) ++#define SCU_PCIE_CONF_BMC_DEV_EN_DMA BIT(14) ++#define SCU_PCIE_CONF_BMC_DEV_EN_E2L BIT(15) ++#define SCU_PCIE_CONF_BMC_DEV_EN_LPC_DECODE BIT(21) + -+ for (i = 0; i < ASPEED_QUEUE_NUM; i++) { -+ struct aspeed_queue_message *queue = &pci_bmc_device->queue[i]; ++#define ASPEED_SCU_BMC_DEV_CLASS 0xC68 + -+ init_waitqueue_head(&queue->tx_wait); -+ init_waitqueue_head(&queue->rx_wait); ++#define ASPEED_QUEUE_NUM 2 ++enum queue_index { ++ QUEUE1 = 0, ++ QUEUE2, ++}; + -+ sysfs_bin_attr_init(&queue->bin); ++struct aspeed_platform { ++ int (*init)(struct platform_device *pdev); ++ ssize_t (*queue_rx)(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, ++ char *buf, loff_t off, size_t count); ++ ssize_t (*queue_tx)(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, ++ char *buf, loff_t off, size_t count); ++}; + -+ /* Queue name index starts from 1 */ -+ queue->bin.attr.name = -+ devm_kasprintf(dev, GFP_KERNEL, "pci-bmc-dev-queue%d", (i + 1)); -+ queue->bin.attr.mode = 0600; -+ queue->bin.read = aspeed_queue_rx; -+ queue->bin.write = aspeed_queue_tx; -+ queue->bin.size = 4; -+ queue->bin.private = queue; ++struct aspeed_queue_message { ++ /* Queue waiters for idle engine */ ++ wait_queue_head_t tx_wait; ++ wait_queue_head_t rx_wait; ++ struct kernfs_node *kn; ++ struct bin_attribute bin; ++ int index; ++ struct aspeed_bmc_device *bmc_device; ++}; ++ ++struct aspeed_bmc_device { ++ unsigned char *host2bmc_base_virt; ++ struct device *dev; ++ struct miscdevice miscdev; ++ int id; ++ void __iomem *reg_base; ++ dma_addr_t bmc_mem_phy; ++ phys_addr_t bmc_mem_size; + -+ ret = sysfs_create_bin_file(&pdev->dev.kobj, &queue->bin); -+ if (ret) { -+ dev_err(dev, "error for bin%d file\n", i); -+ return ret; -+ } ++ int pcie2lpc; ++ int irq; + -+ queue->kn = kernfs_find_and_get(dev->kobj.sd, queue->bin.attr.name); -+ if (!queue->kn) { -+ sysfs_remove_bin_file(&dev->kobj, &queue->bin); -+ return ret; -+ } ++ struct aspeed_queue_message queue[ASPEED_QUEUE_NUM]; + -+ queue->index = i; -+ queue->pci_bmc_device = pci_bmc_device; -+ } ++ const struct aspeed_platform *platform; + -+ return 0; -+} ++ /* AST2700 */ ++ struct regmap *device; ++ struct regmap *e2m; + -+static int aspeed_pci_bmc_device_setup_vuart(struct pci_dev *pdev) -+{ -+ struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); -+ struct device *dev = &pdev->dev; -+ u16 vuart_ioport; -+ int ret, i; ++ struct regmap *scu; ++ int pcie_irq; ++}; + -+ for (i = 0; i < VUART_MAX_PARMS; i++) { -+ /* Assign the line to non-exist device */ -+ pci_bmc_dev->uart_line[i] = -ENOENT; -+ vuart_ioport = 0x3F8 - (i * 0x100); -+ pci_bmc_dev->uart[i].port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; -+ pci_bmc_dev->uart[i].port.uartclk = 115200 * 16; -+ pci_bmc_dev->uart[i].port.irq = -+ pci_irq_vector(pdev, pci_bmc_dev->msi_idx_table[VUART0_MSI + i]); -+ pci_bmc_dev->uart[i].port.dev = dev; -+ pci_bmc_dev->uart[i].port.iotype = UPIO_MEM32; -+ pci_bmc_dev->uart[i].port.iobase = 0; -+ pci_bmc_dev->uart[i].port.mapbase = -+ pci_bmc_dev->message_bar_base + (vuart_ioport << 2); -+ pci_bmc_dev->uart[i].port.membase = 0; -+ pci_bmc_dev->uart[i].port.type = PORT_16550A; -+ pci_bmc_dev->uart[i].port.flags |= (UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE); -+ pci_bmc_dev->uart[i].port.regshift = 2; -+ ret = serial8250_register_8250_port(&pci_bmc_dev->uart[i]); -+ if (ret < 0) { -+ dev_err_probe(dev, ret, "Can't setup PCIe VUART\n"); -+ return ret; -+ } -+ pci_bmc_dev->uart_line[i] = ret; -+ } -+ return 0; ++static struct aspeed_bmc_device *file_aspeed_bmc_device(struct file *file) ++{ ++ return container_of(file->private_data, struct aspeed_bmc_device, ++ miscdev); +} + -+static int aspeed_pci_bmc_device_setup_memory_mapping(struct pci_dev *pdev) ++static int aspeed_bmc_device_mmap(struct file *file, struct vm_area_struct *vma) +{ -+ struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); -+ struct device *dev = &pdev->dev; -+ int ret; ++ 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; + -+ pci_bmc_dev->miscdev.minor = MISC_DYNAMIC_MINOR; -+ pci_bmc_dev->miscdev.name = -+ devm_kasprintf(dev, GFP_KERNEL, "%s%d", DRIVER_NAME, pci_bmc_dev->id); -+ pci_bmc_dev->miscdev.fops = &aspeed_pci_bmc_dev_fops; -+ pci_bmc_dev->miscdev.parent = dev; ++ if (((vma->vm_pgoff << PAGE_SHIFT) + vsize) > bmc_device->bmc_mem_size) ++ return -EINVAL; + -+ ret = misc_register(&pci_bmc_dev->miscdev); -+ if (ret) { -+ pr_err("host bmc register fail %d\n", ret); -+ return ret; -+ } ++ 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 0; +} + -+static int aspeed_pci_bmc_device_setup_mbox(struct pci_dev *pdev) ++static const struct file_operations aspeed_bmc_device_fops = { ++ .owner = THIS_MODULE, ++ .mmap = aspeed_bmc_device_mmap, ++}; ++ ++static ssize_t aspeed_ast2600_queue_rx(struct file *filp, struct kobject *kobj, ++ struct bin_attribute *attr, char *buf, loff_t off, ++ size_t count) +{ -+ struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); -+ struct device *dev = &pdev->dev; ++ struct aspeed_queue_message *queue = attr->private; ++ struct aspeed_bmc_device *bmc_device = queue->bmc_device; ++ int index = queue->index; ++ u32 *data = (u32 *)buf; ++ u32 scu_id; + int ret; + -+ /* setup mbox */ -+ pci_bmc_dev->pcie_sio_decode_addr = pci_bmc_dev->msg_bar_reg + PCIE_DEVICE_SIO_ADDR; -+ writel(0xaa, pci_bmc_dev->pcie_sio_decode_addr); -+ writel(0xa5, pci_bmc_dev->pcie_sio_decode_addr); -+ writel(0xa5, pci_bmc_dev->pcie_sio_decode_addr); -+ writel(0x07, pci_bmc_dev->pcie_sio_decode_addr); -+ writel(0x0e, pci_bmc_dev->pcie_sio_decode_addr + 0x04); -+ /* disable */ -+ writel(0x30, pci_bmc_dev->pcie_sio_decode_addr); -+ writel(0x00, pci_bmc_dev->pcie_sio_decode_addr + 0x04); -+ /* set decode address 0x100 */ -+ writel(0x60, pci_bmc_dev->pcie_sio_decode_addr); -+ writel(0x01, pci_bmc_dev->pcie_sio_decode_addr + 0x04); -+ writel(0x61, pci_bmc_dev->pcie_sio_decode_addr); -+ writel(0x00, pci_bmc_dev->pcie_sio_decode_addr + 0x04); -+ /* enable */ -+ writel(0x30, pci_bmc_dev->pcie_sio_decode_addr); -+ writel(0x01, pci_bmc_dev->pcie_sio_decode_addr + 0x04); -+ pci_bmc_dev->sio_mbox_reg = pci_bmc_dev->msg_bar_reg + 0x400; -+ -+ ret = devm_request_irq(dev, -+ pci_irq_vector(pdev, pci_bmc_dev->msi_idx_table[MBX_MSI]), -+ aspeed_pci_host_mbox_interrupt, IRQF_SHARED, -+ devm_kasprintf(dev, GFP_KERNEL, "aspeed-sio-mbox%d", pci_bmc_dev->id), -+ pci_bmc_dev); -+ if (ret) { -+ pr_err("host bmc device Unable to get IRQ %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} ++ ret = wait_event_interruptible(queue->rx_wait, ++ !(readl(bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS) & ++ ((index == QUEUE1) ? HOST2BMC_Q1_EMPTY : HOST2BMC_Q2_EMPTY))); ++ if (ret) ++ return -EINTR; + -+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); ++ data[0] = readl(bmc_device->reg_base + ++ ((index == QUEUE1) ? ASPEED_BMC_HOST2BMC_Q1 : ASPEED_BMC_HOST2BMC_Q2)); + -+ 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; ++ regmap_read(bmc_device->scu, ASPEED_SCU04, &scu_id); ++ if (scu_id == AST2600A3_SCU04) { ++ writel(BMC2HOST_INT_STS_DOORBELL | BMC2HOST_ENABLE_INTB, ++ bmc_device->reg_base + ASPEED_BMC_BMC2HOST_STS); ++ } else { ++ //A0 : BIT(12) A1 : BIT(15) ++ regmap_update_bits(bmc_device->scu, 0x560, BIT(15), BIT(15)); ++ regmap_update_bits(bmc_device->scu, 0x560, BIT(15), 0); + } -+ return 0; ++ ++ return sizeof(u32); +} + -+static int mmbi_desc_init(struct aspeed_mmbi_channel *chan) ++static ssize_t aspeed_ast2600_queue_tx(struct file *filp, struct kobject *kobj, ++ struct bin_attribute *attr, char *buf, loff_t off, ++ size_t count) +{ -+ struct aspeed_pcie_mmbi *mmbi = chan->mmbi; -+ struct device *dev = chan->dev; -+ struct mmbi_cap_desc desc; -+ u8 __iomem *desc_base = chan->desc_vmem; ++ struct aspeed_queue_message *queue = attr->private; ++ struct aspeed_bmc_device *bmc_device = queue->bmc_device; ++ int index = queue->index; ++ u32 tx_buff; ++ u32 scu_id; + int ret; + -+ /* First, check mmbi signature "#MMBI$" */ -+ ret = mmbi_signature_check(chan); -+ if (ret) { -+ dev_warn(dev, "Check MMBI signature timeout\n"); -+ return ret; -+ } ++ if (count != sizeof(u32)) ++ return -EINVAL; + -+ memcpy_fromio(&desc, chan->desc_vmem, sizeof(desc)); ++ ret = wait_event_interruptible(queue->tx_wait, ++ !(readl(bmc_device->reg_base + ASPEED_BMC_BMC2HOST_STS) & ++ ((index == QUEUE1) ? BMC2HOST_Q1_FULL : BMC2HOST_Q2_FULL))); ++ if (ret) ++ return -EINTR; + -+ /* 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); ++ memcpy(&tx_buff, buf, 4); ++ writel(tx_buff, bmc_device->reg_base + ((index == QUEUE1) ? ASPEED_BMC_BMC2HOST_Q1 : ++ ASPEED_BMC_BMC2HOST_Q2)); + -+ /* 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; ++ /* trigger to host ++ * Only After AST2600A3 support DoorBell MSI ++ */ ++ regmap_read(bmc_device->scu, ASPEED_SCU04, &scu_id); ++ if (scu_id == AST2600A3_SCU04) { ++ writel(BMC2HOST_INT_STS_DOORBELL | BMC2HOST_ENABLE_INTB, ++ bmc_device->reg_base + ASPEED_BMC_BMC2HOST_STS); ++ } else { ++ //A0 : BIT(12) A1 : BIT(15) ++ regmap_update_bits(bmc_device->scu, 0x560, BIT(15), BIT(15)); ++ regmap_update_bits(bmc_device->scu, 0x560, BIT(15), 0); + } -+ 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; -+ } ++ return sizeof(u32); ++} + -+ /* 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; -+ } ++static ssize_t aspeed_ast2700_queue_rx(struct file *filp, struct kobject *kobj, ++ struct bin_attribute *attr, char *buf, loff_t off, ++ size_t count) ++{ ++ struct aspeed_queue_message *queue = attr->private; ++ struct aspeed_bmc_device *bmc_device = queue->bmc_device; ++ int index = queue->index; ++ u32 *data = (u32 *)buf; ++ int ret; + -+ /* 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; -+ } ++ ret = wait_event_interruptible(queue->rx_wait, ++ !(readl(bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS) & ++ ((index == QUEUE1) ? HOST2BMC_Q1_EMPTY : HOST2BMC_Q2_EMPTY))); ++ if (ret) ++ return -EINTR; + -+ /* 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; -+ } ++ data[0] = readl(bmc_device->reg_base + ++ ((index == QUEUE1) ? ASPEED_BMC_HOST2BMC_Q1 : ASPEED_BMC_HOST2BMC_Q2)); + -+ /* 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; ++ writel(BMC2HOST_INT_STS_DOORBELL | BMC2HOST_ENABLE_INTB, ++ bmc_device->reg_base + ASPEED_BMC_BMC2HOST_STS); + -+ /* 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; ++ return sizeof(u32); ++} + -+ 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); ++static ssize_t aspeed_ast2700_queue_tx(struct file *filp, struct kobject *kobj, ++ struct bin_attribute *attr, char *buf, loff_t off, ++ size_t count) ++{ ++ struct aspeed_queue_message *queue = attr->private; ++ struct aspeed_bmc_device *bmc_device = queue->bmc_device; ++ int index = queue->index; ++ u32 tx_buff; ++ int ret; + -+ 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); ++ if (count != sizeof(u32)) ++ return -EINVAL; + -+ /* 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; -+ } ++ ret = wait_event_interruptible(queue->tx_wait, ++ !(readl(bmc_device->reg_base + ASPEED_BMC_BMC2HOST_STS) & ++ ((index == QUEUE1) ? BMC2HOST_Q1_FULL : BMC2HOST_Q2_FULL))); ++ if (ret) ++ return -EINTR; + -+ /* 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; -+ } -+ } ++ memcpy(&tx_buff, buf, 4); ++ writel(tx_buff, bmc_device->reg_base + ((index == QUEUE1) ? ASPEED_BMC_BMC2HOST_Q1 : ++ ASPEED_BMC_BMC2HOST_Q2)); + -+ INIT_WORK(&chan->work, aspeed_mmbi_work_func); ++ writel(BMC2HOST_INT_STS_DOORBELL | BMC2HOST_ENABLE_INTB, ++ bmc_device->reg_base + ASPEED_BMC_BMC2HOST_STS); + -+ return 0; -+err_mismatch: -+ /* Change state to INIT_MISMATCH */ -+ mmbi_set_host_rst(chan, 1); -+ return -EINVAL; ++ return sizeof(u32); +} + -+static int aspeed_pci_mmbi_init(struct aspeed_pcie_mmbi *mmbi) ++/* AST2600 */ ++static irqreturn_t aspeed_bmc_dev_pcie_isr(int irq, void *dev_id) +{ -+ 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; -+ } ++ struct aspeed_bmc_device *bmc_device = dev_id; + -+ /* Initialize MTCP function */ -+ ret = aspeed_mmbi_mctp_init(chan); -+ if (ret) { -+ dev_err(dev, "Unable to init mctp\n"); -+ return ret; -+ } ++ while (!(readl(bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS) & HOST2BMC_Q1_EMPTY)) ++ readl(bmc_device->reg_base + ASPEED_BMC_HOST2BMC_Q1); + -+ /* 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); ++ while (!(readl(bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS) & HOST2BMC_Q2_EMPTY)) ++ readl(bmc_device->reg_base + ASPEED_BMC_HOST2BMC_Q2); + -+ return 0; ++ return IRQ_HANDLED; +} + -+/* 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) ++static irqreturn_t aspeed_bmc_dev_isr(int irq, void *dev_id) +{ -+ 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; ++ struct aspeed_bmc_device *bmc_device = dev_id; ++ u32 host2bmc_q_sts = readl(bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS); + -+ if (pci_bmc_dev->ast2700_soc1) { -+ /* AST2700 SoC1 */ -+ start_bar = 0; -+ mmbi_max_inst = 6; -+ start_msi = 0; -+ } ++ if (host2bmc_q_sts & HOST2BMC_INT_STS_DOORBELL) ++ writel(HOST2BMC_INT_STS_DOORBELL, bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS); + -+ for (i = 0; i < mmbi_max_inst; i++) { -+ mmbi = &pci_bmc_dev->mmbi[i]; ++ if (host2bmc_q_sts & HOST2BMC_ENABLE_INTB) ++ writel(HOST2BMC_ENABLE_INTB, bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS); + -+ /* Get MMBI BAR resource */ -+ mmbi->base = pci_resource_start(pdev, start_bar + i); -+ mmbi->mem_size = pci_resource_len(pdev, start_bar + i); ++ if (host2bmc_q_sts & HOST2BMC_Q1_FULL) ++ dev_info(bmc_device->dev, "Q1 Full\n"); + -+ /* Check if there is bar */ -+ if (!mmbi->mem_size) -+ continue; ++ if (host2bmc_q_sts & HOST2BMC_Q2_FULL) ++ dev_info(bmc_device->dev, "Q2 Full\n"); + -+ mmbi->mem = pci_ioremap_bar(pdev, start_bar + i); -+ if (!mmbi->mem) { -+ mmbi->mem_size = 0; -+ continue; -+ } ++ if (!(readl(bmc_device->reg_base + ASPEED_BMC_BMC2HOST_STS) & BMC2HOST_Q1_FULL)) ++ wake_up_interruptible(&bmc_device->queue[QUEUE1].tx_wait); + -+ 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 (!(readl(bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS) & HOST2BMC_Q1_EMPTY)) ++ wake_up_interruptible(&bmc_device->queue[QUEUE1].rx_wait); + -+ 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); -+ } -+} ++ if (!(readl(bmc_device->reg_base + ASPEED_BMC_BMC2HOST_STS) & BMC2HOST_Q2_FULL)) ++ wake_up_interruptible(&bmc_device->queue[QUEUE2].tx_wait); + -+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); -+ int i; ++ if (!(readl(bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS) & HOST2BMC_Q2_EMPTY)) ++ wake_up_interruptible(&bmc_device->queue[QUEUE2].rx_wait); + -+ for (i = 0; i < ASPEED_QUEUE_NUM; i++) -+ sysfs_remove_bin_file(&pdev->dev.kobj, &pci_bmc_dev->queue[i].bin); ++ return IRQ_HANDLED; +} + -+static void aspeed_pci_host_bmc_device_release_vuart(struct pci_dev *pdev) ++static int aspeed_ast2600_init(struct platform_device *pdev) +{ -+ struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); -+ int i; ++ struct aspeed_bmc_device *bmc_device = platform_get_drvdata(pdev); ++ struct device *dev = &pdev->dev; ++ u32 pcie_config_ctl = SCU_PCIE_CONF_BMC_DEV_EN_IRQ | ++ SCU_PCIE_CONF_BMC_DEV_EN_MMIO | SCU_PCIE_CONF_BMC_DEV_EN; ++ u32 scu_id; + -+ for (i = 0; i < VUART_MAX_PARMS; i++) { -+ if (pci_bmc_dev->uart_line[i] >= 0) -+ serial8250_unregister_port(pci_bmc_dev->uart_line[i]); ++ bmc_device->scu = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,scu"); ++ if (IS_ERR(bmc_device->scu)) { ++ dev_err(&pdev->dev, "failed to find SCU regmap\n"); ++ return PTR_ERR(bmc_device->scu); + } -+} + -+static void aspeed_pci_host_bmc_device_release_memory_mapping(struct pci_dev *pdev) -+{ -+ struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); ++ if (bmc_device->pcie2lpc) ++ pcie_config_ctl |= SCU_PCIE_CONF_BMC_DEV_EN_E2L | ++ SCU_PCIE_CONF_BMC_DEV_EN_LPC_DECODE; + -+ if (!list_empty(&pci_bmc_dev->miscdev.list)) -+ misc_deregister(&pci_bmc_dev->miscdev); ++ regmap_update_bits(bmc_device->scu, ASPEED_SCU_PCIE_CONF_CTRL, ++ pcie_config_ctl, pcie_config_ctl); ++ ++ /* update class code to others as it is a MFD device */ ++ regmap_write(bmc_device->scu, ASPEED_SCU_BMC_DEV_CLASS, 0xff000000); ++ ++#ifdef SCU_TRIGGER_MSI ++ //SCUC24[17]: Enable PCI device 1 INTx/MSI from SCU560[15]. Will be added in next version ++ regmap_update_bits(bmc_device->scu, ASPEED_SCUC20, BIT(11) | BIT(14), BIT(11) | BIT(14)); ++ ++ regmap_read(bmc_device->scu, ASPEED_SCU04, &scu_id); ++ if (scu_id == AST2600A3_SCU04) ++ regmap_update_bits(bmc_device->scu, ASPEED_SCUC24, ++ PCIDEV1_INTX_MSI_HOST2BMC_EN | MSI_ROUTING_MASK, ++ PCIDEV1_INTX_MSI_HOST2BMC_EN | MSI_ROUTING_PCIe2LPC_PCIDEV1); ++ else ++ regmap_update_bits(bmc_device->scu, ASPEED_SCUC24, ++ BIT(17) | BIT(14) | BIT(11), BIT(17) | BIT(14) | BIT(11)); ++#else ++ //SCUC24[18]: Enable PCI device 1 INTx/MSI from Host-to-BMC controller. ++ regmap_update_bits(bmc_device->scu, 0xc24, BIT(18) | BIT(14), BIT(18) | BIT(14)); ++#endif ++ ++ writel((~(bmc_device->bmc_mem_size - 1) & 0xFFFFFFFF) | HOST2BMC_MEM_BAR_ENABLE, ++ bmc_device->reg_base + ASPEED_BMC_MEM_BAR); ++ writel(bmc_device->bmc_mem_phy, bmc_device->reg_base + ASPEED_BMC_MEM_BAR_REMAP); ++ ++ //Setting BMC to Host Q register ++ writel(BMC2HOST_Q2_FULL_UNMASK | BMC2HOST_Q1_FULL_UNMASK | BMC2HOST_ENABLE_INTB, ++ bmc_device->reg_base + ASPEED_BMC_BMC2HOST_STS); ++ writel(HOST2BMC_Q2_FULL_UNMASK | HOST2BMC_Q1_FULL_UNMASK | HOST2BMC_ENABLE_INTB, ++ bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS); ++ ++ return 0; +} + -+static void aspeed_pci_release_mmbi(struct pci_dev *pdev) ++static int aspeed_ast2700_init(struct platform_device *pdev) +{ -+ struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); -+ struct aspeed_pcie_mmbi *mmbi; ++ struct aspeed_bmc_device *bmc_device = platform_get_drvdata(pdev); ++ struct device *dev = &pdev->dev; ++ u32 pcie_config_ctl; ++ u32 scu_id; + int i; + -+ if (pdev->revision != 0x27) -+ return; ++ bmc_device->device = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,device"); ++ if (IS_ERR(bmc_device->device)) { ++ dev_err(&pdev->dev, "failed to find device regmap\n"); ++ return PTR_ERR(bmc_device->device); ++ } + -+ for (i = 0; i < MMBI_MAX_INST; i++) { -+ mmbi = &pci_bmc_dev->mmbi[i]; ++ bmc_device->e2m = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,e2m"); ++ if (IS_ERR(bmc_device->e2m)) { ++ dev_err(&pdev->dev, "failed to find e2m regmap\n"); ++ return PTR_ERR(bmc_device->e2m); ++ } + -+ if (mmbi->mem_size == 0) -+ continue; ++ bmc_device->scu = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,scu"); ++ if (IS_ERR(bmc_device->scu)) { ++ dev_err(&pdev->dev, "failed to find SCU regmap\n"); ++ return PTR_ERR(bmc_device->scu); ++ } + -+ cancel_work_sync(&mmbi->chan.work); ++ if (bmc_device->pcie2lpc) { ++ pcie_config_ctl = SCU_PCIE_CONF_BMC_DEV_EN_E2L | ++ SCU_PCIE_CONF_BMC_DEV_EN_LPC_DECODE; ++ regmap_update_bits(bmc_device->scu, SCU0_PCIE_CONF_CTRL, ++ pcie_config_ctl, pcie_config_ctl); ++ } + -+ mmbi_set_host_rdy(&mmbi->chan, 0); -+ mmbi_set_host_up(&mmbi->chan, 0); ++ /* update class code to others as it is a MFD device */ ++ regmap_write(bmc_device->device, 0x18, 0xff000027); + -+ unregister_netdev(mmbi->chan.ndev); ++ /* MSI */ ++ regmap_update_bits(bmc_device->device, 0x74, GENMASK(7, 4), BIT(7) | (5 << 4)); ++ /* EnPCIaMSI:BIT(25), EnPCIaIntA:BIT(17), EnPCIaMst:BIT(9), EnPCIaDev:BIT(1) */ ++ regmap_read(bmc_device->scu, SCU0_REVISION_ID, &scu_id); ++ if (scu_id & REVISION_ID) ++ regmap_update_bits(bmc_device->device, 0x70, ++ BIT(25) | BIT(17) | BIT(9) | BIT(1), ++ BIT(25) | BIT(17) | BIT(9) | BIT(1)); ++ else ++ /* Disable MSI[bit25] in ast2700A0 int only */ ++ regmap_update_bits(bmc_device->device, 0x70, ++ BIT(17) | BIT(9) | BIT(1), ++ BIT(25) | BIT(17) | BIT(9) | BIT(1)); + -+ if (mmbi->mem) -+ pci_iounmap(pdev, mmbi->mem); -+ if (mmbi->irq != 0) -+ devm_free_irq(&pdev->dev, mmbi->irq, mmbi); ++ /* bar size check for 4k align */ ++ for (i = 1; i < 16; i++) { ++ if ((bmc_device->bmc_mem_size / 4096) == (1 << (i - 1))) ++ break; ++ } ++ if (i == 16) { ++ i = 0; ++ dev_warn(bmc_device->dev, ++ "Bar size not align for 4K : %dK\n", (u32)bmc_device->bmc_mem_size / 1024); + } -+} + -+static int aspeed_pci_host_setup(struct pci_dev *pdev) -+{ -+ struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); -+ int rc = 0; ++ /* ++ * BAR assign in scu ++ * ((bar_mem / 4k) << 8) | per_size ++ */ ++ regmap_write(bmc_device->device, 0x1c, ((bmc_device->bmc_mem_phy) >> 4) | i); + -+ /* Get share memory BAR */ -+ pci_bmc_dev->mem_bar_base = pci_resource_start(pdev, 0); -+ pci_bmc_dev->mem_bar_size = pci_resource_len(pdev, 0); -+ pci_bmc_dev->mem_bar_reg = pci_ioremap_bar(pdev, 0); -+ if (!pci_bmc_dev->mem_bar_reg) -+ return -ENOMEM; ++ if (bmc_device->id == 0) ++ /* Node 0 Bar 0 */ ++ regmap_write(bmc_device->e2m, 0x108, ((bmc_device->bmc_mem_phy) >> 4) | i); ++ else ++ /* Node 1 Bar 0 */ ++ regmap_write(bmc_device->e2m, 0x128, ((bmc_device->bmc_mem_phy) >> 4) | i); + -+ /* Get Message BAR */ -+ pci_bmc_dev->message_bar_base = pci_resource_start(pdev, 1); -+ pci_bmc_dev->message_bar_size = pci_resource_len(pdev, 1); -+ pci_bmc_dev->msg_bar_reg = pci_ioremap_bar(pdev, 1); -+ if (!pci_bmc_dev->msg_bar_reg) { -+ rc = -ENOMEM; -+ goto out_free0; -+ } ++ /* Setting BMC to Host Q register */ ++ writel(BMC2HOST_Q2_FULL_UNMASK | BMC2HOST_Q1_FULL_UNMASK | BMC2HOST_ENABLE_INTB, ++ bmc_device->reg_base + ASPEED_BMC_BMC2HOST_STS); ++ writel(HOST2BMC_Q2_FULL_UNMASK | HOST2BMC_Q1_FULL_UNMASK | HOST2BMC_ENABLE_INTB, ++ bmc_device->reg_base + ASPEED_BMC_HOST2BMC_STS); + -+ /* AST2600 ERRTA40: dummy read */ -+ if (pdev->revision < 0x27) -+ (void)__raw_readl((void __iomem *)pci_bmc_dev->msg_bar_reg); ++ return 0; ++} + -+ rc = aspeed_pci_bmc_device_setup_queue(pdev); -+ if (rc) { -+ pr_err("Cannot setup Queue Message"); -+ goto out_free1; -+ } ++static int aspeed_bmc_device_setup_queue(struct platform_device *pdev) ++{ ++ struct aspeed_bmc_device *bmc_device = platform_get_drvdata(pdev); ++ struct device *dev = &pdev->dev; ++ int ret, i; + -+ rc = aspeed_pci_bmc_device_setup_memory_mapping(pdev); -+ if (rc) { -+ pr_err("Cannot setup Memory Mapping"); -+ goto out_free_queue; -+ } ++ for (i = 0; i < ASPEED_QUEUE_NUM; i++) { ++ struct aspeed_queue_message *queue = &bmc_device->queue[i]; + -+ rc = aspeed_pci_bmc_device_setup_mbox(pdev); -+ if (rc) { -+ pr_err("Cannot setup Mailnbox"); -+ goto out_free_mmapping; -+ } ++ init_waitqueue_head(&queue->tx_wait); ++ init_waitqueue_head(&queue->rx_wait); + -+ rc = aspeed_pci_bmc_device_setup_vuart(pdev); -+ if (rc) { -+ pr_err("Cannot setup Virtual UART"); -+ goto out_free_mbox; -+ } ++ sysfs_bin_attr_init(&queue->bin); + -+ rc = devm_request_irq(&pdev->dev, pci_irq_vector(pdev, pci_bmc_dev->msi_idx_table[BMC_MSI]), -+ aspeed_pci_host_bmc_device_interrupt, IRQF_SHARED, -+ pci_bmc_dev->miscdev.name, pci_bmc_dev); -+ if (rc) { -+ pr_err("Get BMC DEVICE IRQ failed. (err=%d)\n", rc); -+ goto out_free_uart; -+ } ++ /* Queue name index starts from 1 */ ++ queue->bin.attr.name = ++ devm_kasprintf(dev, GFP_KERNEL, "bmc-dev-queue%d", (i + 1)); ++ queue->bin.attr.mode = 0600; ++ queue->bin.read = bmc_device->platform->queue_rx; ++ queue->bin.write = bmc_device->platform->queue_tx; ++ queue->bin.size = 4; ++ queue->bin.private = queue; + -+ /* Setup AST2700 PCIe MMBI device */ -+ aspeed_pci_bmc_device_setup_mmbi(pdev); ++ ret = sysfs_create_bin_file(&pdev->dev.kobj, &queue->bin); ++ if (ret) { ++ dev_err(dev, "error for bin%d file\n", i); ++ return ret; ++ } + -+ return 0; ++ queue->kn = kernfs_find_and_get(dev->kobj.sd, queue->bin.attr.name); ++ if (!queue->kn) { ++ sysfs_remove_bin_file(&dev->kobj, &queue->bin); ++ return ret; ++ } + -+out_free_uart: -+ aspeed_pci_host_bmc_device_release_vuart(pdev); -+out_free_mbox: -+ devm_free_irq(&pdev->dev, pci_irq_vector(pdev, pci_bmc_dev->msi_idx_table[MBX_MSI]), -+ pci_bmc_dev); -+out_free_mmapping: -+ aspeed_pci_host_bmc_device_release_memory_mapping(pdev); -+out_free_queue: -+ aspeed_pci_host_bmc_device_release_queue(pdev); -+out_free1: -+ pci_iounmap(pdev, pci_bmc_dev->msg_bar_reg); -+out_free0: -+ pci_iounmap(pdev, pci_bmc_dev->mem_bar_reg); ++ queue->index = i; ++ queue->bmc_device = bmc_device; ++ } + -+ pci_release_regions(pdev); -+ return rc; ++ return 0; +} + -+static int aspeed_pci_host_mmbi_device_setup(struct pci_dev *pdev) ++static int aspeed_bmc_device_setup_memory_mapping(struct platform_device *pdev) +{ -+ aspeed_pci_bmc_device_setup_mmbi(pdev); ++ struct aspeed_bmc_device *bmc_device = platform_get_drvdata(pdev); ++ struct device *dev = &pdev->dev; ++ int ret; ++ ++ bmc_device->miscdev.minor = MISC_DYNAMIC_MINOR; ++ bmc_device->miscdev.name = devm_kasprintf(dev, GFP_KERNEL, "bmc-device%d", bmc_device->id); ++ bmc_device->miscdev.fops = &aspeed_bmc_device_fops; ++ bmc_device->miscdev.parent = dev; ++ ret = misc_register(&bmc_device->miscdev); ++ if (ret) { ++ dev_err(dev, "Unable to register device\n"); ++ return ret; ++ } ++ + return 0; +} + -+static struct aspeed_platform aspeed_pcie_host[] = { -+ { .setup = aspeed_pci_host_setup }, -+ { .setup = aspeed_pci_host_mmbi_device_setup }, -+ { 0 } ++static struct aspeed_platform ast2600_plaform = { ++ .init = aspeed_ast2600_init, ++ .queue_rx = aspeed_ast2600_queue_rx, ++ .queue_tx = aspeed_ast2600_queue_tx +}; + -+static int aspeed_pci_host_bmc_device_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ++static struct aspeed_platform ast2700_plaform = { ++ .init = aspeed_ast2700_init, ++ .queue_rx = aspeed_ast2700_queue_rx, ++ .queue_tx = aspeed_ast2700_queue_tx ++}; ++ ++static const struct of_device_id aspeed_bmc_device_of_matches[] = { ++ { .compatible = "aspeed,ast2600-bmc-device", .data = &ast2600_plaform }, ++ { .compatible = "aspeed,ast2700-bmc-device", .data = &ast2700_plaform }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, aspeed_bmc_device_of_matches); ++ ++static int aspeed_bmc_device_probe(struct platform_device *pdev) +{ -+ struct aspeed_pci_bmc_dev *pci_bmc_dev; -+ int rc = 0; ++ struct aspeed_bmc_device *bmc_device; ++ struct device *dev = &pdev->dev; ++ struct resource res; ++ const void *md = of_device_get_match_data(dev); ++ struct device_node *np; ++ int ret = 0, i; + -+ pr_info("ASPEED BMC PCI ID %04x:%04x, IRQ=%u\n", pdev->vendor, pdev->device, pdev->irq); ++ if (!md) ++ return -ENODEV; + -+ pci_bmc_dev = devm_kzalloc(&pdev->dev, sizeof(*pci_bmc_dev), GFP_KERNEL); -+ if (!pci_bmc_dev) ++ bmc_device = devm_kzalloc(&pdev->dev, sizeof(struct aspeed_bmc_device), GFP_KERNEL); ++ if (!bmc_device) + return -ENOMEM; ++ dev_set_drvdata(dev, bmc_device); + -+ /* Get platform id */ -+ pci_bmc_dev->driver_data = ent->driver_data; -+ pci_bmc_dev->platform = &aspeed_pcie_host[ent->driver_data]; ++ bmc_device->platform = md; + -+ pci_bmc_dev->id = ida_simple_get(&bmc_device_ida, 0, 0, GFP_KERNEL); -+ if (pci_bmc_dev->id < 0) -+ return pci_bmc_dev->id; ++ bmc_device->id = of_alias_get_id(dev->of_node, "bmcdev"); ++ if (bmc_device->id < 0) ++ bmc_device->id = 0; + -+ rc = pci_enable_device(pdev); -+ if (rc) { -+ dev_err(&pdev->dev, "pci_enable_device() returned error %d\n", rc); -+ return rc; ++ bmc_device->dev = dev; ++ bmc_device->reg_base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(bmc_device->reg_base)) ++ goto out_region; ++ ++ 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; + } + -+ pci_set_master(pdev); -+ pci_set_drvdata(pdev, pci_bmc_dev); ++ 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; ++ } + -+ /* Prepare IRQ resource */ -+ aspeed_pci_setup_irq_resource(pdev); ++ of_node_put(np); + -+ /* Setup BMC PCI device */ -+ rc = pci_bmc_dev->platform->setup(pdev); -+ if (rc) { -+ dev_err(&pdev->dev, "ASPEED PCIe Host device returned error %d\n", rc); -+ pci_free_irq_vectors(pdev); -+ pci_disable_device(pdev); -+ return rc; ++ bmc_device->bmc_mem_phy = res.start; ++ bmc_device->bmc_mem_size = resource_size(&res); ++ ++ 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; ++ } ++ 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 0; -+} ++ ret = aspeed_bmc_device_setup_queue(pdev); ++ if (ret) { ++ dev_err(dev, "Cannot setup queue message"); ++ goto out_irq; ++ } + -+static void aspeed_pci_host_bmc_device_remove(struct pci_dev *pdev) -+{ -+ struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); ++ ret = aspeed_bmc_device_setup_memory_mapping(pdev); ++ if (ret) { ++ dev_err(dev, "Cannot setup memory mapping misc"); ++ goto out_free_queue; ++ } + -+ 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); ++ if (of_property_read_bool(dev->of_node, "pcie2lpc")) ++ bmc_device->pcie2lpc = 1; + -+ 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); ++ ret = bmc_device->platform->init(pdev); ++ if (ret) { ++ dev_err(dev, "Initialize bmc device failed\n"); ++ goto out_free_misc; + } + -+ aspeed_pci_release_mmbi(pdev); ++ bmc_device->pcie_irq = platform_get_irq(pdev, 1); ++ if (bmc_device->pcie_irq < 0) { ++ dev_warn(&pdev->dev, ++ "platform get of pcie irq[=%d] failed!\n", bmc_device->pcie_irq); ++ } else { ++ ret = devm_request_irq(&pdev->dev, bmc_device->pcie_irq, ++ aspeed_bmc_dev_pcie_isr, IRQF_SHARED, ++ dev_name(&pdev->dev), bmc_device); ++ if (ret < 0) { ++ dev_warn(dev, "Failed to request PCI-E IRQ %d.\n", ret); ++ bmc_device->pcie_irq = -1; ++ } ++ } + -+ ida_simple_remove(&bmc_device_ida, pci_bmc_dev->id); ++ dev_info(dev, "aspeed bmc device: driver successfully loaded.\n"); + -+ pci_iounmap(pdev, pci_bmc_dev->msg_bar_reg); -+ pci_iounmap(pdev, pci_bmc_dev->mem_bar_reg); ++ return 0; + -+ pci_free_irq_vectors(pdev); -+ pci_release_regions(pdev); -+ pci_disable_device(pdev); ++out_free_misc: ++ misc_deregister(&bmc_device->miscdev); ++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); ++ dev_warn(dev, "aspeed bmc device: driver init failed (ret=%d)!\n", ret); ++ return ret; +} + -+/** -+ * This table holds the list of (VendorID,DeviceID) supported by this driver -+ * -+ */ -+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 }, -+ { -+ 0, -+ } -+}; ++static void aspeed_bmc_device_remove(struct platform_device *pdev) ++{ ++ struct aspeed_bmc_device *bmc_device = platform_get_drvdata(pdev); ++ int i; + -+MODULE_DEVICE_TABLE(pci, aspeed_host_bmc_dev_pci_ids); ++ for (i = 0; i < ASPEED_QUEUE_NUM; i++) ++ sysfs_remove_bin_file(&pdev->dev.kobj, &bmc_device->queue[i].bin); ++ misc_deregister(&bmc_device->miscdev); ++ devm_free_irq(&pdev->dev, bmc_device->irq, bmc_device); ++ devm_free_irq(&pdev->dev, bmc_device->pcie_irq, bmc_device); + -+static struct pci_driver aspeed_host_bmc_dev_driver = { -+ .name = DRIVER_NAME, -+ .id_table = aspeed_host_bmc_dev_pci_ids, -+ .probe = aspeed_pci_host_bmc_device_probe, -+ .remove = aspeed_pci_host_bmc_device_remove, -+}; ++ iounmap(bmc_device->reg_base); + -+static int __init aspeed_host_bmc_device_init(void) -+{ -+ return pci_register_driver(&aspeed_host_bmc_dev_driver); ++ devm_kfree(&pdev->dev, bmc_device); +} + -+static void aspeed_host_bmc_device_exit(void) -+{ -+ /* unregister pci driver */ -+ pci_unregister_driver(&aspeed_host_bmc_dev_driver); -+} ++static struct platform_driver aspeed_bmc_device_driver = { ++ .probe = aspeed_bmc_device_probe, ++ .remove = aspeed_bmc_device_remove, ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = aspeed_bmc_device_of_matches, ++ }, ++}; + -+late_initcall(aspeed_host_bmc_device_init); -+module_exit(aspeed_host_bmc_device_exit); ++module_platform_driver(aspeed_bmc_device_driver); + +MODULE_AUTHOR("Ryan Chen "); -+MODULE_DESCRIPTION("ASPEED Host BMC DEVICE Driver"); ++MODULE_DESCRIPTION("ASPEED 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 2026-04-08 18:03:48.310705320 +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 2026-04-08 18:03:48.310705320 +0000 -@@ -0,0 +1,406 @@ +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 +@@ -0,0 +1,255 @@ +// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright 2017 IBM Corporation -+ * Copyright 2021 Aspeed Technology Inc. -+ */ -+#include ++// Copyright (C) ASPEED Technology Inc. ++#include ++#include ++#include +#include +#include ++#include +#include -+#include -+#include ++#include +#include +#include +#include -+#include -+ -+#define DEVICE_NAME "aspeed-mbox" -+ -+#define ASPEED_MBOX_DR(dr, n) (dr + (n * 4)) -+#define ASPEED_MBOX_STR(str, n) (str + (n / 8) * 4) -+#define ASPEED_MBOX_BIE(bie, n) (bie + (n / 8) * 4) -+#define ASPEED_MBOX_HIE(hie, n) (hie + (n / 8) * 4) + -+#define ASPEED_MBOX_BCR_RECV BIT(7) -+#define ASPEED_MBOX_BCR_MASK BIT(1) -+#define ASPEED_MBOX_BCR_SEND BIT(0) ++#define DEVICE_NAME "aspeed-disp-intf" + -+/* ioctl code */ -+#define ASPEED_MBOX_IOCTL 0xA3 -+#define ASPEED_MBOX_IOCTL_GET_SIZE \ -+ _IOR(ASPEED_MBOX_IOCTL, 0, struct aspeed_mbox_ioctl_data) ++#define AST2700_SCU_CHIP_ID 0x0 ++#define SCU_CPU_REVISION_ID_HW GENMASK(23, 16) + -+struct aspeed_mbox_ioctl_data { -+ unsigned int data; -+}; ++#define AST2700_SCU_PIN_SEL 0x414 ++#define AST2700_SCU_D1PLL_SEL GENMASK(13, 12) ++#define AST2700_SCU_DAC_SRC_SEL GENMASK(11, 10) ++#define AST2700_SCU_DP_SRC_SEL GENMASK(9, 8) + -+struct aspeed_mbox_model { -+ unsigned int dr_num; ++#define AST2600_SCU_PIN_SEL 0x0C0 ++#define AST2600_SCU_DP_SRC_SEL BIT(18) ++#define AST2600_SCU_DAC_SRC_SEL BIT(16) + -+ /* offsets to the MBOX registers */ -+ unsigned int dr; -+ unsigned int str; -+ unsigned int bcr; -+ unsigned int hcr; -+ unsigned int bie; -+ unsigned int hie; ++struct aspeed_disp_intf_config { ++ u8 version; ++ u32 dac_src_sel; ++ u32 dac_src_max; ++ u32 dac_src_min; ++ u32 dp_src_sel; ++ u32 dp_src_max; ++ u32 dp_src_min; +}; + -+struct aspeed_mbox { ++struct aspeed_disp_intf { ++ struct device *dev; + struct miscdevice miscdev; -+ struct regmap *map; -+ unsigned int base; -+ wait_queue_head_t queue; -+ struct mutex mutex; -+ const struct aspeed_mbox_model *model; ++ struct regmap *scu; ++ const struct aspeed_disp_intf_config *config; +}; + -+static atomic_t aspeed_mbox_open_count = ATOMIC_INIT(0); -+ -+static u8 aspeed_mbox_inb(struct aspeed_mbox *mbox, int reg) -+{ -+ /* -+ * The mbox registers are actually only one byte but are addressed -+ * four bytes apart. The other three bytes are marked 'reserved', -+ * they *should* be zero but lets not rely on it. -+ * I am going to rely on the fact we can casually read/write to them... -+ */ -+ unsigned int val = 0xff; /* If regmap throws an error return 0xff */ -+ int rc = regmap_read(mbox->map, mbox->base + reg, &val); ++static int dac_src, dp_src; + -+ if (rc) -+ dev_err(mbox->miscdev.parent, "regmap_read() failed with " -+ "%d (reg: 0x%08x)\n", rc, reg); ++static const struct aspeed_disp_intf_config ast2600_config = { ++ .version = 6, ++ .dac_src_sel = AST2600_SCU_PIN_SEL, ++ .dac_src_max = 1, ++ .dac_src_min = 0, ++ .dp_src_sel = AST2600_SCU_PIN_SEL, ++ .dp_src_max = 1, ++ .dp_src_min = 0, ++}; + -+ return val & 0xff; -+} ++static const struct aspeed_disp_intf_config ast2700_config = { ++ .version = 7, ++ .dac_src_sel = AST2700_SCU_PIN_SEL, ++ .dac_src_max = 2, ++ .dac_src_min = 0, ++ .dp_src_sel = AST2700_SCU_PIN_SEL, ++ .dp_src_max = 2, ++ .dp_src_min = 0, ++}; + -+static void aspeed_mbox_outb(struct aspeed_mbox *mbox, u8 data, int reg) ++static ssize_t dac_src_show(struct device *dev, ++ struct device_attribute *attr, char *buf) +{ -+ int rc = regmap_write(mbox->map, mbox->base + reg, data); ++ struct aspeed_disp_intf *intf = dev_get_drvdata(dev); ++ const struct aspeed_disp_intf_config *config = intf->config; ++ u32 val; + -+ if (rc) -+ dev_err(mbox->miscdev.parent, "regmap_write() failed with " -+ "%d (data: %u reg: 0x%08x)\n", rc, data, reg); ++ regmap_read(intf->scu, config->dac_src_sel, &val); ++ dac_src = (config->version == 6) ++ ? FIELD_GET(AST2600_SCU_DAC_SRC_SEL, val) ++ : FIELD_GET(AST2700_SCU_DAC_SRC_SEL, val); ++ return sysfs_emit(buf, "%d\n", dac_src); +} + -+static struct aspeed_mbox *file_mbox(struct file *file) ++static ssize_t dac_src_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) +{ -+ return container_of(file->private_data, struct aspeed_mbox, miscdev); -+} ++ struct aspeed_disp_intf *intf = dev_get_drvdata(dev); ++ const struct aspeed_disp_intf_config *config = intf->config; ++ int src, res; + -+static int aspeed_mbox_open(struct inode *inode, struct file *file) -+{ -+ struct aspeed_mbox *mbox = file_mbox(file); -+ const struct aspeed_mbox_model *model = mbox->model; ++ res = kstrtoint(buf, 0, &src); ++ if (res) ++ return res; + -+ if (atomic_inc_return(&aspeed_mbox_open_count) == 1) { -+ /* -+ * Clear the interrupt status bit if it was left on and unmask -+ * interrupts. -+ * ASPEED_MBOX_BCR_RECV bit is W1C, this also unmasks in 1 step -+ */ -+ aspeed_mbox_outb(mbox, ASPEED_MBOX_BCR_RECV, model->bcr); -+ return 0; ++ if (src < config->dac_src_min || src > config->dac_src_max) { ++ dev_err(intf->dev, "Invalid dac_src(max:%d, min:%d)\n", ++ config->dac_src_max, config->dac_src_min); ++ return -1; + } + -+ atomic_dec(&aspeed_mbox_open_count); -+ return -EBUSY; ++ dac_src = src; ++ if (config->version == 6) { ++ regmap_update_bits(intf->scu, config->dac_src_sel, AST2600_SCU_DAC_SRC_SEL, ++ FIELD_PREP(AST2600_SCU_DAC_SRC_SEL, src)); ++ } else { ++ u32 id; ++ u32 mask = AST2700_SCU_DAC_SRC_SEL; ++ u32 val = FIELD_PREP(AST2700_SCU_DAC_SRC_SEL, src); ++ ++ // D1PLL used in A0 only ++ regmap_read(intf->scu, AST2700_SCU_CHIP_ID, &id); ++ if (FIELD_GET(SCU_CPU_REVISION_ID_HW, id) != 0) { ++ mask |= AST2700_SCU_D1PLL_SEL; ++ val |= FIELD_PREP(AST2700_SCU_D1PLL_SEL, src); ++ } ++ ++ regmap_update_bits(intf->scu, config->dac_src_sel, mask, val); ++ } ++ return count; +} + -+static ssize_t aspeed_mbox_read(struct file *file, char __user *buf, -+ size_t count, loff_t *ppos) ++static DEVICE_ATTR_RW(dac_src); ++ ++static ssize_t dp_src_show(struct device *dev, struct device_attribute *attr, ++ char *buf) +{ -+ struct aspeed_mbox *mbox = file_mbox(file); -+ const struct aspeed_mbox_model *model = mbox->model; -+ char __user *p = buf; -+ ssize_t ret; -+ int i; ++ struct aspeed_disp_intf *intf = dev_get_drvdata(dev); ++ const struct aspeed_disp_intf_config *config = intf->config; ++ u32 val; + -+ if (!access_ok(buf, count)) -+ return -EFAULT; ++ regmap_read(intf->scu, config->dp_src_sel, &val); ++ dp_src = (config->version == 6) ++ ? FIELD_GET(AST2600_SCU_DP_SRC_SEL, val) ++ : FIELD_GET(AST2700_SCU_DP_SRC_SEL, val); ++ return sysfs_emit(buf, "%d\n", dp_src); ++} + -+ if (count + *ppos > model->dr_num) -+ return -EINVAL; ++static ssize_t dp_src_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct aspeed_disp_intf *intf = dev_get_drvdata(dev); ++ const struct aspeed_disp_intf_config *config = intf->config; ++ int src, res; + -+ if (file->f_flags & O_NONBLOCK) { -+ if (!(aspeed_mbox_inb(mbox, model->bcr) & -+ ASPEED_MBOX_BCR_RECV)) -+ return -EAGAIN; -+ } else if (wait_event_interruptible(mbox->queue, -+ aspeed_mbox_inb(mbox, model->bcr) & -+ ASPEED_MBOX_BCR_RECV)) { -+ return -ERESTARTSYS; -+ } ++ res = kstrtoint(buf, 0, &src); ++ if (res) ++ return res; + -+ mutex_lock(&mbox->mutex); ++ if (src < config->dp_src_min || src > config->dp_src_max) { ++ dev_err(intf->dev, "Invalid dp_src(max:%d, min:%d)\n", ++ config->dp_src_max, config->dp_src_min); ++ return -1; ++ } + -+ for (i = *ppos; count > 0 && i < model->dr_num; i++) { -+ uint8_t reg = aspeed_mbox_inb(mbox, ASPEED_MBOX_DR(model->dr, i)); ++ dp_src = src; ++ if (config->version == 6) { ++ regmap_update_bits(intf->scu, config->dp_src_sel, AST2600_SCU_DP_SRC_SEL, ++ FIELD_PREP(AST2600_SCU_DP_SRC_SEL, src)); ++ } else { ++ u32 val; + -+ ret = __put_user(reg, p); -+ if (ret) -+ goto out_unlock; ++ regmap_update_bits(intf->scu, config->dp_src_sel, AST2700_SCU_DP_SRC_SEL, ++ FIELD_PREP(AST2700_SCU_DP_SRC_SEL, src)); + -+ p++; -+ count--; ++ // D1PLL used in A0 only ++ regmap_read(intf->scu, AST2700_SCU_CHIP_ID, &val); ++ if (FIELD_GET(SCU_CPU_REVISION_ID_HW, val) == 0) { ++ regmap_update_bits(intf->scu, config->dp_src_sel, AST2700_SCU_D1PLL_SEL, ++ FIELD_PREP(AST2700_SCU_D1PLL_SEL, src)); ++ } + } + -+ /* ASPEED_MBOX_BCR_RECV bit is write to clear, this also unmasks in 1 step */ -+ aspeed_mbox_outb(mbox, ASPEED_MBOX_BCR_RECV, model->bcr); -+ ret = p - buf; -+ -+out_unlock: -+ mutex_unlock(&mbox->mutex); -+ return ret; ++ return count; +} + -+static ssize_t aspeed_mbox_write(struct file *file, const char __user *buf, -+ size_t count, loff_t *ppos) ++static DEVICE_ATTR_RW(dp_src); ++ ++static struct attribute *aspeed_disp_intf_attrs[] = { ++ &dev_attr_dac_src.attr, ++ &dev_attr_dp_src.attr, ++ NULL, ++}; ++ ++static const struct attribute_group aspeed_disp_intf_attgrp = { ++ .name = NULL, ++ .attrs = aspeed_disp_intf_attrs, ++}; ++ ++static int aspeed_disp_intf_probe(struct platform_device *pdev) +{ -+ struct aspeed_mbox *mbox = file_mbox(file); -+ const struct aspeed_mbox_model *model = mbox->model; -+ const char __user *p = buf; -+ ssize_t ret; -+ char c; -+ int i; ++ struct aspeed_disp_intf *intf; ++ struct device *dev = &pdev->dev; ++ int ret; + -+ if (!access_ok(buf, count)) -+ return -EFAULT; ++ intf = devm_kzalloc(&pdev->dev, sizeof(struct aspeed_disp_intf), GFP_KERNEL); ++ if (!intf) ++ return -ENOMEM; + -+ if (count + *ppos > model->dr_num) -+ return -EINVAL; ++ dev_set_drvdata(&pdev->dev, intf); + -+ mutex_lock(&mbox->mutex); ++ intf->config = of_device_get_match_data(&pdev->dev); ++ if (!intf->config) ++ return -ENODEV; + -+ for (i = *ppos; count > 0 && i < model->dr_num; i++) { -+ ret = __get_user(c, p); -+ if (ret) -+ goto out_unlock; ++ intf->dev = dev; ++ intf->scu = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); ++ if (IS_ERR(intf->scu)) { ++ dev_err(dev, "failed to find SCU regmap\n"); ++ return PTR_ERR(intf->scu); ++ } + -+ aspeed_mbox_outb(mbox, c, ASPEED_MBOX_DR(model->dr, i)); -+ p++; -+ count--; ++ intf->miscdev.minor = MISC_DYNAMIC_MINOR; ++ intf->miscdev.name = DEVICE_NAME; ++ intf->miscdev.parent = dev; ++ ret = misc_register(&intf->miscdev); ++ if (ret) { ++ dev_err(dev, "Unable to register device\n"); ++ return ret; + } + -+ aspeed_mbox_outb(mbox, ASPEED_MBOX_BCR_SEND, model->bcr); -+ ret = p - buf; ++ ret = sysfs_create_group(&dev->kobj, &aspeed_disp_intf_attgrp); ++ if (ret != 0) ++ dev_warn(dev, "failed to register attributes\n"); + -+out_unlock: -+ mutex_unlock(&mbox->mutex); -+ return ret; ++ return 0; +} + -+static __poll_t aspeed_mbox_poll(struct file *file, poll_table *wait) ++static void aspeed_disp_intf_remove(struct platform_device *pdev) +{ -+ struct aspeed_mbox *mbox = file_mbox(file); -+ const struct aspeed_mbox_model *model = mbox->model; -+ __poll_t mask = 0; ++ struct aspeed_disp_intf *intf = platform_get_drvdata(pdev); + -+ poll_wait(file, &mbox->queue, wait); ++ sysfs_remove_group(&intf->dev->kobj, &aspeed_disp_intf_attgrp); ++ misc_deregister(&intf->miscdev); ++ devm_kfree(&pdev->dev, intf); ++} + -+ if (aspeed_mbox_inb(mbox, model->bcr) & ASPEED_MBOX_BCR_RECV) -+ mask |= POLLIN; ++static const struct of_device_id aspeed_disp_intf_of_matches[] = { ++ { .compatible = "aspeed,ast2600-disp-intf", .data = &ast2600_config }, ++ { .compatible = "aspeed,ast2700-disp-intf", .data = &ast2700_config }, ++ {}, ++}; + -+ return mask; -+} ++static struct platform_driver aspeed_disp_intf_driver = { ++ .probe = aspeed_disp_intf_probe, ++ .remove = aspeed_disp_intf_remove, ++ .driver = { ++ .name = DEVICE_NAME, ++ .of_match_table = aspeed_disp_intf_of_matches, ++ }, ++}; + -+static int aspeed_mbox_release(struct inode *inode, struct file *file) -+{ -+ atomic_dec(&aspeed_mbox_open_count); -+ return 0; -+} ++module_platform_driver(aspeed_disp_intf_driver); + -+static long aspeed_mbox_ioctl(struct file *file, unsigned int cmd, -+ unsigned long param) -+{ -+ long ret = 0; -+ struct aspeed_mbox *mbox = file_mbox(file); -+ const struct aspeed_mbox_model *model = mbox->model; -+ struct aspeed_mbox_ioctl_data data; ++MODULE_DEVICE_TABLE(of, aspeed_disp_intf_of_matches); ++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__ + -+ switch (cmd) { -+ case ASPEED_MBOX_IOCTL_GET_SIZE: -+ data.data = model->dr_num; -+ if (copy_to_user((void __user *)param, &data, sizeof(data))) -+ ret = -EFAULT; -+ break; -+ default: -+ ret = -ENOTTY; -+ break; -+ } ++#include ++#include + -+ return ret; -+} ++/* ++ * 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 + -+static const struct file_operations aspeed_mbox_fops = { -+ .owner = THIS_MODULE, -+ .llseek = no_seek_end_llseek, -+ .read = aspeed_mbox_read, -+ .write = aspeed_mbox_write, -+ .open = aspeed_mbox_open, -+ .release = aspeed_mbox_release, -+ .poll = aspeed_mbox_poll, -+ .unlocked_ioctl = aspeed_mbox_ioctl, ++/* ++ * 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; +}; + -+static irqreturn_t aspeed_mbox_irq(int irq, void *arg) -+{ -+ struct aspeed_mbox *mbox = arg; -+ const struct aspeed_mbox_model *model = mbox->model; -+ -+ if (!(aspeed_mbox_inb(mbox, model->bcr) & ASPEED_MBOX_BCR_RECV)) -+ return IRQ_NONE; ++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; + -+ /* -+ * Leave the status bit set so that we know the data is for us, -+ * clear it once it has been read. -+ */ ++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; + -+ /* Mask it off, we'll clear it when we the data gets read */ -+ aspeed_mbox_outb(mbox, ASPEED_MBOX_BCR_MASK, model->bcr); ++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; + -+ wake_up(&mbox->queue); -+ return IRQ_HANDLED; -+} ++struct espi_perif_cmplt { ++ uint8_t cyc; ++ uint8_t len_h : 4; ++ uint8_t tag : 4; ++ uint8_t len_l; ++ uint8_t data[]; ++} __packed; + -+static int aspeed_mbox_config_irq(struct aspeed_mbox *mbox, -+ struct platform_device *pdev) -+{ -+ const struct aspeed_mbox_model *model = mbox->model; -+ struct device *dev = &pdev->dev; -+ int i, rc, irq; ++struct espi_oob_msg { ++ uint8_t cyc; ++ uint8_t len_h : 4; ++ uint8_t tag : 4; ++ uint8_t len_l; ++ uint8_t data[]; ++}; + -+ irq = irq_of_parse_and_map(dev->of_node, 0); -+ if (!irq) -+ return -ENODEV; ++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; + -+ rc = devm_request_irq(dev, irq, aspeed_mbox_irq, -+ IRQF_SHARED, DEVICE_NAME, mbox); -+ if (rc < 0) { -+ dev_err(dev, "Unable to request IRQ %d\n", irq); -+ return rc; -+ } ++struct espi_flash_cmplt { ++ uint8_t cyc; ++ uint8_t len_h : 4; ++ uint8_t tag : 4; ++ uint8_t len_l; ++ uint8_t data[]; ++} __packed; + -+ /* -+ * Disable all register based interrupts. -+ */ -+ for (i = 0; i < model->dr_num / 8; ++i) -+ aspeed_mbox_outb(mbox, 0x00, ASPEED_MBOX_BIE(model->bie, i)); ++#define ESPI_MAX_PLD_LEN BIT(12) + -+ /* These registers are write one to clear. Clear them. */ -+ for (i = 0; i < model->dr_num / 8; ++i) -+ aspeed_mbox_outb(mbox, 0xff, ASPEED_MBOX_STR(model->str, i)); ++/* ++ * 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 + -+ aspeed_mbox_outb(mbox, ASPEED_MBOX_BCR_RECV, model->bcr); -+ return 0; -+} ++/* ++ * 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) + -+static int aspeed_mbox_probe(struct platform_device *pdev) -+{ -+ struct aspeed_mbox *mbox; -+ struct device *dev; -+ int rc; ++struct aspeed_espi_ioc { ++ uint32_t pkt_len; ++ uint8_t *pkt; ++}; + -+ dev = &pdev->dev; ++/* ++ * 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) + -+ mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); -+ if (!mbox) -+ return -ENOMEM; ++#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 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++// Copyright (C) ASPEED Technology Inc. + -+ dev_set_drvdata(&pdev->dev, mbox); ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ rc = of_property_read_u32(dev->of_node, "reg", &mbox->base); -+ if (rc) { -+ dev_err(dev, "Couldn't read reg device tree property\n"); -+ return rc; -+ } ++#include ++#include ++#include ++#include ++#include + -+ mbox->model = of_device_get_match_data(dev); -+ if (IS_ERR(mbox->model)) { -+ dev_err(dev, "Couldn't get model data\n"); -+ return -ENODEV; -+ } ++#include "aspeed-pcie-mmbi.h" + -+ mbox->map = syscon_node_to_regmap( -+ pdev->dev.parent->of_node); -+ if (IS_ERR(mbox->map)) { -+ dev_err(dev, "Couldn't get regmap\n"); -+ return -ENODEV; -+ } ++#define PCI_BMC_HOST2BMC_Q1 0x30000 ++#define PCI_BMC_HOST2BMC_Q2 0x30010 ++#define PCI_BMC_BMC2HOST_Q1 0x30020 ++#define PCI_BMC_BMC2HOST_Q2 0x30030 ++#define PCI_BMC_BMC2HOST_STS 0x30040 ++#define BMC2HOST_INT_STS_DOORBELL BIT(31) ++#define BMC2HOST_ENABLE_INTB BIT(30) + -+ mutex_init(&mbox->mutex); -+ init_waitqueue_head(&mbox->queue); ++#define BMC2HOST_Q1_FULL BIT(27) ++#define BMC2HOST_Q1_EMPTY BIT(26) ++#define BMC2HOST_Q2_FULL BIT(25) ++#define BMC2HOST_Q2_EMPTY BIT(24) ++#define BMC2HOST_Q1_FULL_UNMASK BIT(23) ++#define BMC2HOST_Q1_EMPTY_UNMASK BIT(22) ++#define BMC2HOST_Q2_FULL_UNMASK BIT(21) ++#define BMC2HOST_Q2_EMPTY_UNMASK BIT(20) + -+ mbox->miscdev.minor = MISC_DYNAMIC_MINOR; -+ mbox->miscdev.name = DEVICE_NAME; -+ mbox->miscdev.fops = &aspeed_mbox_fops; -+ mbox->miscdev.parent = dev; -+ rc = misc_register(&mbox->miscdev); -+ if (rc) { -+ dev_err(dev, "Unable to register device\n"); -+ return rc; -+ } ++#define PCI_BMC_HOST2BMC_STS 0x30044 ++#define HOST2BMC_INT_STS_DOORBELL BIT(31) ++#define HOST2BMC_ENABLE_INTB BIT(30) + -+ rc = aspeed_mbox_config_irq(mbox, pdev); -+ if (rc) { -+ dev_err(dev, "Failed to configure IRQ\n"); -+ misc_deregister(&mbox->miscdev); -+ return rc; -+ } ++#define HOST2BMC_Q1_FULL BIT(27) ++#define HOST2BMC_Q1_EMPTY BIT(26) ++#define HOST2BMC_Q2_FULL BIT(25) ++#define HOST2BMC_Q2_EMPTY BIT(24) ++#define HOST2BMC_Q1_FULL_UNMASK BIT(23) ++#define HOST2BMC_Q1_EMPTY_UNMASK BIT(22) ++#define HOST2BMC_Q2_FULL_UNMASK BIT(21) ++#define HOST2BMC_Q2_EMPTY_UNMASK BIT(20) + -+ return 0; -+} ++static DEFINE_IDA(bmc_device_ida); + -+static void aspeed_mbox_remove(struct platform_device *pdev) -+{ -+ struct aspeed_mbox *mbox = dev_get_drvdata(&pdev->dev); ++#define MMBI_MAX_INST 6 ++#define VUART_MAX_PARMS 2 ++#define ASPEED_QUEUE_NUM 2 ++#define MAX_MSI_NUM 8 + -+ misc_deregister(&mbox->miscdev); -+} ++enum aspeed_platform_id { ++ ASPEED, ++ ASPEED_AST2700_SOC1, ++}; + -+static const struct aspeed_mbox_model ast2400_model = { -+ .dr_num = 16, -+ .dr = 0x0, -+ .str = 0x40, -+ .bcr = 0x48, -+ .hcr = 0x4c, -+ .bie = 0x50, -+ .hie = 0x58, ++enum queue_index { ++ QUEUE1 = 0, ++ QUEUE2, +}; + -+static const struct aspeed_mbox_model ast2600_model = { -+ .dr_num = 32, -+ .dr = 0x0, -+ .str = 0x80, -+ .bcr = 0x90, -+ .hcr = 0x94, -+ .bie = 0xa0, -+ .hie = 0xb0, ++enum msi_index { ++ BMC_MSI, ++ MBX_MSI, ++ VUART0_MSI, ++ VUART1_MSI, ++ MMBI0_MSI, ++ MMBI1_MSI, ++ MMBI2_MSI, ++ MMBI3_MSI, +}; + -+static const struct of_device_id aspeed_mbox_match[] = { -+ { .compatible = "aspeed,ast2400-mbox", -+ .data = &ast2400_model }, -+ { .compatible = "aspeed,ast2500-mbox", -+ .data = &ast2400_model }, -+ { .compatible = "aspeed,ast2600-mbox", -+ .data = &ast2600_model }, -+ { }, ++/* 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 }; ++ ++struct aspeed_platform { ++ int (*setup)(struct pci_dev *pdev); +}; + -+static struct platform_driver aspeed_mbox_driver = { -+ .driver = { -+ .name = DEVICE_NAME, -+ .of_match_table = aspeed_mbox_match, -+ }, -+ .probe = aspeed_mbox_probe, -+ .remove = aspeed_mbox_remove, ++struct aspeed_queue_message { ++ /* Queue waiters for idle engine */ ++ wait_queue_head_t tx_wait; ++ wait_queue_head_t rx_wait; ++ struct kernfs_node *kn; ++ struct bin_attribute bin; ++ int index; ++ struct aspeed_pci_bmc_dev *pci_bmc_device; +}; + -+module_platform_driver(aspeed_mbox_driver); -+MODULE_DEVICE_TABLE(of, aspeed_mbox_match); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Cyril Bur "); -+MODULE_AUTHOR("Chia-Wei Wang -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++struct aspeed_pcie_mmbi { ++ resource_size_t base; ++ resource_size_t mem_size; ++ void __iomem *mem; ++ u32 segment_size; ++ int irq; ++ int id; ++ struct aspeed_mmbi_channel chan; ++ const char *dev_name; ++}; + -+#define DEVICE_NAME "aspeed-lpc-pcc" ++struct aspeed_pci_bmc_dev { ++ struct device *dev; ++ struct miscdevice miscdev; ++ struct aspeed_platform *platform; ++ kernel_ulong_t driver_data; ++ int id; + -+static DEFINE_IDA(aspeed_pcc_ida); ++ unsigned long mem_bar_base; ++ unsigned long mem_bar_size; ++ void __iomem *mem_bar_reg; + -+#define HICR5 0x80 -+#define HICR5_EN_SNP0W BIT(0) -+#define HICR5_EN_SNP1W BIT(2) -+#define HICR6 0x084 -+#define HICR6_EN2BMODE BIT(19) -+#define SNPWADR 0x090 -+#define PCCR6 0x0c4 -+#define PCCR6_DMA_CUR_ADDR GENMASK(27, 0) -+#define PCCR4 0x0d0 -+#define PCCR4_DMA_ADDRL_MASK GENMASK(31, 0) -+#define PCCR4_DMA_ADDRL_SHIFT 0 -+#define PCCR5 0x0d4 -+#define PCCR5_DMA_ADDRH_MASK GENMASK(27, 24) -+#define PCCR5_DMA_ADDRH_SHIFT 24 -+#define PCCR5_DMA_LEN_MASK GENMASK(23, 0) -+#define PCCR5_DMA_LEN_SHIFT 0 -+#define HICRB 0x100 -+#define HICRB_ENSNP0D BIT(14) -+#define HICRB_ENSNP1D BIT(15) -+#define PCCR0 0x130 -+#define PCCR0_EN_DMA_INT BIT(31) -+#define PCCR0_EN_DMA_MODE BIT(14) -+#define PCCR0_ADDR_SEL_MASK GENMASK(13, 12) -+#define PCCR0_ADDR_SEL_SHIFT 12 -+#define PCCR0_RX_TRIG_LVL_MASK GENMASK(10, 8) -+#define PCCR0_RX_TRIG_LVL_SHIFT 8 -+#define PCCR0_CLR_RX_FIFO BIT(7) -+#define PCCR0_MODE_SEL_MASK GENMASK(5, 4) -+#define PCCR0_MODE_SEL_SHIFT 4 -+#define PCCR0_EN_RX_TMOUT_INT BIT(2) -+#define PCCR0_EN_RX_AVAIL_INT BIT(1) -+#define PCCR0_EN BIT(0) -+#define PCCR1 0x134 -+#define PCCR1_BASE_ADDR_MASK GENMASK(15, 0) -+#define PCCR1_BASE_ADDR_SHIFT 0 -+#define PCCR1_DONT_CARE_BITS_MASK GENMASK(21, 16) -+#define PCCR1_DONT_CARE_BITS_SHIFT 16 -+#define PCCR2 0x138 -+#define PCCR2_INT_STATUS_PATTERN_B BIT(16) -+#define PCCR2_INT_STATUS_PATTERN_A BIT(8) -+#define PCCR2_INT_STATUS_DMA_DONE BIT(4) -+#define PCCR2_INT_STATUS_DATA_RDY PCCR2_INT_STATUS_DMA_DONE -+#define PCCR2_INT_STATUS_RX_OVER BIT(3) -+#define PCCR2_INT_STATUS_RX_TMOUT BIT(2) -+#define PCCR2_INT_STATUS_RX_AVAIL BIT(1) -+#define PCCR3 0x13c -+#define PCCR3_FIFO_DATA_MASK GENMASK(7, 0) ++ unsigned long message_bar_base; ++ unsigned long message_bar_size; ++ void __iomem *msg_bar_reg; + -+#define PCC_DMA_BUFSZ (256 * SZ_1K) ++ void __iomem *pcie_sio_decode_addr; + -+/* 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, -+ PCC_FIFO_THR_2_EIGHTH, -+ PCC_FIFO_THR_3_EIGHTH, -+ PCC_FIFO_THR_4_EIGHTH, -+ PCC_FIFO_THR_5_EIGHTH, -+ PCC_FIFO_THR_6_EIGHTH, -+ PCC_FIFO_THR_7_EIGHTH, -+}; ++ struct aspeed_queue_message queue[ASPEED_QUEUE_NUM]; + -+enum pcc_record_mode { -+ PCC_REC_1B, -+ PCC_REC_2B, -+ PCC_REC_4B, -+ PCC_REC_FULL, -+}; ++ void __iomem *sio_mbox_reg; ++ struct uart_8250_port uart[VUART_MAX_PARMS]; ++ int uart_line[VUART_MAX_PARMS]; + -+enum pcc_port_hbits_select { -+ PCC_PORT_HBITS_SEL_NONE, -+ PCC_PORT_HBITS_SEL_45, -+ PCC_PORT_HBITS_SEL_67, -+ PCC_PORT_HBITS_SEL_89, -+}; ++ /* Interrupt ++ * The index of array is using to enum msi_index ++ */ ++ int *msi_idx_table; + -+struct aspeed_pcc_dma { -+ uint32_t rptr; -+ uint8_t *virt; -+ dma_addr_t addr; -+ uint32_t size; -+}; ++ bool ast2700_soc1; + -+struct aspeed_pcc_ctrl { -+ struct device *dev; -+ struct regmap *regmap; -+ int irq; -+ uint32_t port; -+ struct aspeed_pcc_dma dma; -+ struct kfifo fifo; -+ wait_queue_head_t wq; -+ struct miscdevice mdev; -+ int mdev_id; -+ spinlock_t lock; /* protects access to the FIFO and DMA pointer */ ++ /* AST2700 MMBI */ ++ struct aspeed_pcie_mmbi mmbi[MMBI_MAX_INST]; ++ int mmbi_start_msi; +}; + -+static inline bool is_valid_rec_mode(uint32_t mode) ++#define PCIE_DEVICE_SIO_ADDR (0x2E * 4) ++#define BMC_MULTI_MSI 32 ++ ++#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) +{ -+ return (mode > PCC_REC_FULL) ? false : true; ++ struct host_ros hros; ++ ++ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); ++ ++ return hros.b_rdy; +} + -+static inline bool is_valid_high_bits_select(uint32_t sel) ++static u8 mmbi_get_bmc_up(struct aspeed_mmbi_channel *chan) +{ -+ return (sel > PCC_PORT_HBITS_SEL_89) ? false : true; ++ struct host_ros hros; ++ ++ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); ++ ++ return hros.b_up; +} + -+static ssize_t aspeed_pcc_file_read(struct file *file, char __user *buffer, -+ size_t count, loff_t *ppos) ++static u8 mmbi_get_bmc_rst(struct aspeed_mmbi_channel *chan) +{ -+ int rc; -+ unsigned int copied; -+ struct aspeed_pcc_ctrl *pcc = container_of(file->private_data, -+ struct aspeed_pcc_ctrl, -+ mdev); ++ struct host_ros hros; + -+ if (kfifo_is_empty(&pcc->fifo)) { -+ if (file->f_flags & O_NONBLOCK) -+ return -EAGAIN; ++ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); + -+ rc = wait_event_interruptible(pcc->wq, -+ !kfifo_is_empty(&pcc->fifo)); -+ if (rc == -ERESTARTSYS) -+ return -EINTR; -+ } ++ return hros.b_rst; ++} + -+ rc = kfifo_to_user(&pcc->fifo, buffer, count, &copied); ++static u8 mmbi_get_host_rst(struct aspeed_mmbi_channel *chan) ++{ ++ struct host_rws hrws; + -+ return rc ? rc : copied; ++ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); ++ ++ return hrws.h_rst; +} + -+static __poll_t aspeed_pcc_file_poll(struct file *file, -+ struct poll_table_struct *pt) ++static u8 mmbi_get_host_up(struct aspeed_mmbi_channel *chan) +{ -+ struct aspeed_pcc_ctrl *pcc = container_of(file->private_data, -+ struct aspeed_pcc_ctrl, -+ mdev); ++ struct host_rws hrws; + -+ poll_wait(file, &pcc->wq, pt); ++ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); + -+ return !kfifo_is_empty(&pcc->fifo) ? POLLIN : 0; ++ return hrws.h_up; +} + -+static const struct file_operations pcc_fops = { -+ .owner = THIS_MODULE, -+ .read = aspeed_pcc_file_read, -+ .poll = aspeed_pcc_file_poll, -+}; ++static void mmbi_set_host_rst(struct aspeed_mmbi_channel *chan, bool set) ++{ ++ struct host_rws hrws; + -+static irqreturn_t aspeed_pcc_dma_isr(int irq, void *arg) ++ 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) +{ -+ uint32_t reg, rptr, wptr; -+ struct aspeed_pcc_ctrl *pcc = (struct aspeed_pcc_ctrl *)arg; -+ struct kfifo *fifo = &pcc->fifo; ++ struct host_rws hrws; + -+ spin_lock(&pcc->lock); -+ regmap_write_bits(pcc->regmap, PCCR2, PCCR2_INT_STATUS_DMA_DONE, PCCR2_INT_STATUS_DMA_DONE); ++ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); ++ hrws.h_rdy = set; ++ memcpy_toio(chan->hrws_vmem, &hrws, sizeof(hrws)); ++} + -+ regmap_read(pcc->regmap, PCCR6, ®); -+ wptr = (reg & PCCR6_DMA_CUR_ADDR) - (pcc->dma.addr & PCCR6_DMA_CUR_ADDR); -+ rptr = pcc->dma.rptr; ++static void mmbi_set_host_up(struct aspeed_mmbi_channel *chan, bool set) ++{ ++ struct host_rws hrws; + -+ /* 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); -+ } ++ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); ++ hrws.h_up = set; ++ memcpy_toio(chan->hrws_vmem, &hrws, sizeof(hrws)); ++} + -+ pcc->dma.rptr = wptr; -+ spin_unlock(&pcc->lock); ++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; + -+ wake_up_interruptible(&pcc->wq); ++ 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); + -+ return IRQ_HANDLED; ++ 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 irqreturn_t aspeed_pcc_isr(int irq, void *arg) ++static u8 mmbi_get_state(struct aspeed_mmbi_channel *chan) +{ -+ uint32_t sts; -+ struct aspeed_pcc_ctrl *pcc = (struct aspeed_pcc_ctrl *)arg; ++ u8 state = 0; + -+ regmap_read(pcc->regmap, PCCR2, &sts); ++ 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); + -+ if (!(sts & (PCCR2_INT_STATUS_RX_TMOUT | -+ PCCR2_INT_STATUS_RX_AVAIL | -+ PCCR2_INT_STATUS_DMA_DONE))) -+ return IRQ_NONE; ++ dev_dbg(chan->dev, "MMBI state: 0x%x\n", state); + -+ return aspeed_pcc_dma_isr(irq, arg); ++ return state; +} + -+/* -+ * A2600-15 AP note -+ * -+ * SW workaround to prevent generating Non-Fatal-Error (NFE) -+ * eSPI response when PCC is used for port I/O byte snooping -+ * over eSPI. -+ */ -+static int aspeed_a2600_15(struct aspeed_pcc_ctrl *pcc, struct device *dev) ++static void raise_h2b_interrupt(struct aspeed_mmbi_channel *chan) +{ -+ u32 hicr5_en, hicrb_en; ++ if (!chan->bmc_int_en) ++ return; + -+ /* abort if snoop is enabled */ -+ regmap_read(pcc->regmap, HICR5, &hicr5_en); -+ if (hicr5_en & (HICR5_EN_SNP0W | HICR5_EN_SNP1W)) { -+ dev_err(dev, "A2600-15 should be applied with snoop disabled\n"); -+ return -EPERM; -+ } ++ writeb(chan->bmc_int_value, chan->desc_vmem + chan->bmc_int_location); ++} + -+ /* set SNPWADR of snoop device */ -+ regmap_write(pcc->regmap, SNPWADR, pcc->port | ((pcc->port + 2) << 16)); ++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; + -+ /* set HICRB[15:14]=11b to enable ACCEPT response for SNPWADR */ -+ hicrb_en = HICRB_ENSNP0D | HICRB_ENSNP1D; -+ regmap_update_bits(pcc->regmap, HICRB, hicrb_en, hicrb_en); ++ switch (current_state) { ++ case INIT_COMPLETED: ++ dev_dbg(dev, "Get INIT_COMPLETED state from BMC"); + -+ /* set HICR6[19] to extend SNPWADR to 2x range */ -+ regmap_update_bits(pcc->regmap, HICR6, HICR6_EN2BMODE, HICR6_EN2BMODE); ++ 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 aspeed_pcc_enable(struct aspeed_pcc_ctrl *pcc, struct device *dev) ++static int mmbi_bmc_up_check(struct aspeed_mmbi_channel *chan) +{ -+ int rc; -+ -+ rc = aspeed_a2600_15(pcc, dev); -+ if (rc) -+ return rc; -+ -+ /* record mode: Set 2-Byte mode. */ -+ regmap_update_bits(pcc->regmap, PCCR0, -+ PCCR0_MODE_SEL_MASK, -+ PCC_REC_2B << PCCR0_MODE_SEL_SHIFT); ++ u64 __timeout_us = 1000; ++ ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); + -+ /* port address */ -+ regmap_update_bits(pcc->regmap, PCCR1, -+ PCCR1_BASE_ADDR_MASK, -+ pcc->port << PCCR1_BASE_ADDR_SHIFT); ++ for (;;) { ++ enum mmbi_state current_state = mmbi_get_state(chan); + -+ /* Set address high bits selection to 0b01 for address bit[5:4] */ -+ regmap_update_bits(pcc->regmap, PCCR0, -+ PCCR0_ADDR_SEL_MASK, -+ PCC_PORT_HBITS_SEL_45 << PCCR0_ADDR_SEL_SHIFT); ++ if (current_state == INIT_COMPLETED) ++ break; ++ if (__timeout_us && ktime_compare(ktime_get(), __timeout) > 0) ++ return -EAGAIN; ++ } + -+ /* Set LPC don't care address to 0x3 for port 80~83h */ -+ regmap_update_bits(pcc->regmap, PCCR1, -+ PCCR1_DONT_CARE_BITS_MASK, -+ 0x3 << PCCR1_DONT_CARE_BITS_SHIFT); ++ return 0; ++} + -+ /* set DMA ring buffer size and enable interrupts */ -+ regmap_write(pcc->regmap, PCCR4, pcc->dma.addr & 0xffffffff); -+#ifdef CONFIG_ARM64 -+ regmap_update_bits(pcc->regmap, PCCR5, PCCR5_DMA_ADDRH_MASK, -+ (pcc->dma.addr >> 32) << PCCR5_DMA_ADDRH_SHIFT); -+#endif -+ regmap_update_bits(pcc->regmap, PCCR5, PCCR5_DMA_LEN_MASK, -+ (pcc->dma.size / 4) << PCCR5_DMA_LEN_SHIFT); -+ regmap_update_bits(pcc->regmap, PCCR0, -+ PCCR0_EN_DMA_INT | PCCR0_EN_DMA_MODE, -+ PCCR0_EN_DMA_INT | PCCR0_EN_DMA_MODE); ++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; + -+ regmap_update_bits(pcc->regmap, PCCR0, -+ PCCR0_RX_TRIG_LVL_MASK, -+ PCC_FIFO_THR_2_EIGHTH << PCCR0_RX_TRIG_LVL_SHIFT); ++ h2b_wp = GET_H2B_WRITE_POINTER(chan); ++ b2h_rp = GET_B2H_READ_POINTER(chan); + -+ regmap_update_bits(pcc->regmap, PCCR0, PCCR0_EN, PCCR0_EN); ++ dev_dbg(dev, "MMBI HRWS - b2h_rp: 0x%0x, h2b_wp: 0x%0x\n", b2h_rp, h2b_wp); + -+ return 0; -+} ++ /* 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; + -+static int aspeed_pcc_disable(struct aspeed_pcc_ctrl *pcc) -+{ -+ /* Disable PCC and DMA Mode for safety */ -+ regmap_update_bits(pcc->regmap, PCCR0, PCCR0_EN | PCCR0_EN_DMA_MODE, 0); ++ /* 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; + -+ /* Clear Rx FIFO. */ -+ regmap_update_bits(pcc->regmap, PCCR0, PCCR0_CLR_RX_FIFO, 1); ++ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); + -+ /* Clear All interrupts status. */ -+ regmap_write(pcc->regmap, PCCR2, -+ PCCR2_INT_STATUS_RX_OVER | PCCR2_INT_STATUS_DMA_DONE | -+ PCCR2_INT_STATUS_PATTERN_A | PCCR2_INT_STATUS_PATTERN_B); ++ 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); + -+ return 0; ++ if (w_len != 0) ++ raise_h2b_interrupt(chan); +} + -+static int aspeed_pcc_probe(struct platform_device *pdev) ++static int get_mmbi_header(struct aspeed_mmbi_channel *chan, u32 *data_length, u8 *type, ++ u32 *unread_data_len, u8 *padding) +{ -+ int rc; -+ struct aspeed_pcc_ctrl *pcc; -+ struct device *dev = &pdev->dev; -+ uint32_t fifo_size = PAGE_SIZE; ++ u32 h2b_wp, h2b_rp, b2h_wp, b2h_rp; ++ struct mmbi_header header; + -+ pcc = devm_kzalloc(dev, sizeof(*pcc), GFP_KERNEL); -+ if (!pcc) -+ return -ENOMEM; ++ 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); + -+ pcc->regmap = syscon_node_to_regmap(dev->parent->of_node); -+ if (IS_ERR(pcc->regmap)) -+ return dev_err_probe(dev, PTR_ERR(pcc->regmap), "Couldn't get regmap\n"); ++ if (b2h_wp >= b2h_rp) ++ *unread_data_len = b2h_wp - b2h_rp; ++ else ++ *unread_data_len = chan->b2h_cb_size - b2h_rp + b2h_wp; + -+ rc = of_property_read_u32(dev->of_node, "pcc-ports", &pcc->port); -+ if (rc) { -+ dev_err(dev, "no pcc ports configured\n"); -+ return rc; ++ 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; + } + -+ 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_dbg(chan->dev, "READ MMBI header from: %p\n", chan->b2h_cb_vmem + b2h_rp); + -+ pcc->dma.size = PCC_DMA_BUFSZ; -+ pcc->dma.virt = dmam_alloc_coherent(dev, -+ pcc->dma.size, -+ &pcc->dma.addr, -+ GFP_KERNEL); -+ if (!pcc->dma.virt) { -+ dev_err(dev, "cannot allocate DMA buffer\n"); -+ return -ENOMEM; ++ /* 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); + } + -+ fifo_size = roundup(pcc->dma.size, PAGE_SIZE); -+ rc = kfifo_alloc(&pcc->fifo, fifo_size, GFP_KERNEL); -+ if (rc) -+ return rc; ++ *data_length = (header.pkt_len << 2) - sizeof(header) - header.pkt_pad; ++ *padding = header.pkt_pad; ++ *type = header.pkt_type; + -+ spin_lock_init(&pcc->lock); ++ return 0; ++} + -+ /* Disable PCC to clean up DMA buffer before request IRQ. */ -+ rc = aspeed_pcc_disable(pcc); -+ if (rc) { -+ dev_err(dev, "Couldn't disable PCC\n"); -+ goto err_free_kfifo; -+ } ++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; + -+ pcc->irq = platform_get_irq(pdev, 0); -+ if (pcc->irq < 0) { -+ rc = pcc->irq; -+ goto err_free_kfifo; ++ /* 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; + } + -+ rc = devm_request_irq(dev, pcc->irq, aspeed_pcc_isr, 0, DEVICE_NAME, pcc); -+ if (rc < 0) { -+ dev_err(dev, "Couldn't request IRQ %d\n", pcc->irq); -+ goto err_free_kfifo; -+ } ++ get_h2b_avail_buf_len(chan, &avail_buf_len); + -+ init_waitqueue_head(&pcc->wq); ++ dev_dbg(dev, "H2B buffer empty space: %zd\n", avail_buf_len); + -+ pcc->mdev_id = ida_alloc(&aspeed_pcc_ida, GFP_KERNEL); -+ if (pcc->mdev_id < 0) { -+ dev_err(dev, "Couldn't allocate ID\n"); -+ goto err_free_kfifo; -+ } ++ /* Header size */ ++ total_len = len + 4; + -+ pcc->mdev.parent = dev; -+ pcc->mdev.minor = MISC_DYNAMIC_MINOR; -+ pcc->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s%d", DEVICE_NAME, -+ pcc->mdev_id); -+ pcc->mdev.fops = &pcc_fops; -+ rc = misc_register(&pcc->mdev); -+ if (rc) { -+ dev_err(dev, "Couldn't register misc device\n"); -+ goto err_free_ida; -+ } ++ padding = total_len & 0x3; ++ if (padding) ++ padding = 4 - padding; ++ total_len += padding; + -+ rc = aspeed_pcc_enable(pcc, dev); -+ if (rc) { -+ dev_err(dev, "Couldn't enable PCC\n"); -+ goto err_dereg_mdev; -+ } ++ /* 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; + -+ dev_set_drvdata(dev, pcc); ++ /* Fill multi-protocol header */ ++ header.pkt_type = type; ++ header.pkt_len = total_len >> 2; ++ header.pkt_pad = padding; + -+ return 0; ++ wt_offset = GET_H2B_WRITE_POINTER(chan); ++ end_offset = chan->h2b_cb_size; + -+err_dereg_mdev: -+ misc_deregister(&pcc->mdev); ++ /* 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); ++ } + -+err_free_ida: -+ ida_free(&aspeed_pcc_ida, pcc->mdev_id); ++ /* 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; ++ } + -+err_free_kfifo: -+ kfifo_free(&pcc->fifo); ++ update_host_rws(chan, total_len, 0); + -+ return rc; ++ return 0; +} + -+static void aspeed_pcc_remove(struct platform_device *pdev) ++static void aspeed_mmbi_read(struct aspeed_mmbi_channel *chan, char *buffer, size_t len, u8 padding) +{ -+ struct device *dev = &pdev->dev; -+ struct aspeed_pcc_ctrl *pcc = dev_get_drvdata(dev); -+ -+ kfifo_free(&pcc->fifo); -+ ida_free(&aspeed_pcc_ida, pcc->mdev_id); -+ misc_deregister(&pcc->mdev); -+} ++ struct device *dev = chan->dev; ++ ssize_t rd_offset; ++ u32 b2h_rp; + -+static const struct of_device_id aspeed_pcc_table[] = { -+ { .compatible = "aspeed,ast2600-lpc-pcc" }, -+ { }, -+}; ++ 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; + -+static struct platform_driver aspeed_pcc_driver = { -+ .driver = { -+ .name = "aspeed-pcc", -+ .of_match_table = aspeed_pcc_table, -+ }, -+ .probe = aspeed_pcc_probe, -+ .remove = aspeed_pcc_remove, -+}; ++ /* 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); + -+module_platform_driver(aspeed_pcc_driver); ++ 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; + -+MODULE_AUTHOR("Chia-Wei Wang "); -+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 2026-04-08 18:03:48.310705320 +0000 -@@ -11,7 +11,7 @@ - */ - - #include --#include -+#include - #include - #include - #include -@@ -25,7 +25,6 @@ - - #define DEVICE_NAME "aspeed-lpc-snoop" - --#define NUM_SNOOP_CHANNELS 2 - #define SNOOP_FIFO_SIZE 2048 - - #define HICR5 0x80 -@@ -36,6 +35,7 @@ - #define HICR6 0x84 - #define HICR6_STR_SNP0W BIT(0) - #define HICR6_STR_SNP1W BIT(1) -+#define HICR6_NFE_WA BIT(20) - #define SNPWADR 0x90 - #define SNPWADR_CH0_MASK GENMASK(15, 0) - #define SNPWADR_CH0_SHIFT 0 -@@ -57,7 +57,22 @@ - unsigned int has_hicrb_ensnp; - }; - -+enum aspeed_lpc_snoop_index { -+ ASPEED_LPC_SNOOP_INDEX_0 = 0, -+ ASPEED_LPC_SNOOP_INDEX_1 = 1, -+ ASPEED_LPC_SNOOP_INDEX_MAX = ASPEED_LPC_SNOOP_INDEX_1, -+}; ++ 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); + -+struct aspeed_lpc_snoop_channel_cfg { -+ enum aspeed_lpc_snoop_index index; -+ u32 hicr5_en; -+ u32 snpwadr_mask; -+ u32 snpwadr_shift; -+ u32 hicrb_en; -+}; ++ rd_offset = 0; ++ memcpy_fromio(buffer + chunk_len, chan->b2h_cb_vmem + rd_offset, ++ len - chunk_len); ++ } + - struct aspeed_lpc_snoop_channel { -+ const struct aspeed_lpc_snoop_channel_cfg *cfg; - bool enabled; - struct kfifo fifo; - wait_queue_head_t wq; -@@ -67,10 +82,28 @@ - struct aspeed_lpc_snoop { - struct regmap *regmap; - int irq; -- struct clk *clk; -- struct aspeed_lpc_snoop_channel chan[NUM_SNOOP_CHANNELS]; -+ struct aspeed_lpc_snoop_channel chan[ASPEED_LPC_SNOOP_INDEX_MAX + 1]; - }; - -+static const struct aspeed_lpc_snoop_channel_cfg channel_cfgs[ASPEED_LPC_SNOOP_INDEX_MAX + 1] = { -+ { -+ .index = ASPEED_LPC_SNOOP_INDEX_0, -+ .hicr5_en = HICR5_EN_SNP0W | HICR5_ENINT_SNP0W, -+ .snpwadr_mask = SNPWADR_CH0_MASK, -+ .snpwadr_shift = SNPWADR_CH0_SHIFT, -+ .hicrb_en = HICRB_ENSNP0D, -+ }, -+ { -+ .index = ASPEED_LPC_SNOOP_INDEX_1, -+ .hicr5_en = HICR5_EN_SNP1W | HICR5_ENINT_SNP1W, -+ .snpwadr_mask = SNPWADR_CH1_MASK, -+ .snpwadr_shift = SNPWADR_CH1_SHIFT, -+ .hicrb_en = HICRB_ENSNP1D, -+ }, -+}; ++ update_host_rws(chan, 0, len + sizeof(struct mmbi_header) + padding); ++} + -+static DEFINE_IDA(aspeed_lpc_snoop_ida); ++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; + - static struct aspeed_lpc_snoop_channel *snoop_file_to_chan(struct file *file) - { - return container_of(file->private_data, -@@ -136,12 +169,19 @@ - return IRQ_NONE; - - /* Check if one of the snoop channels is interrupting */ -- reg &= (HICR6_STR_SNP0W | HICR6_STR_SNP1W); -- if (!reg) -+ if (!(reg & (HICR6_STR_SNP0W | HICR6_STR_SNP1W))) - return IRQ_NONE; - -- /* Ack pending IRQs */ -- regmap_write(lpc_snoop->regmap, HICR6, reg); -+ /* Check if NFE WA is set */ -+ if (reg & HICR6_NFE_WA) { -+ /* Ack pending IRQs with keeping NFE WA */ -+ regmap_write(lpc_snoop->regmap, HICR6, -+ (HICR6_STR_SNP0W | HICR6_STR_SNP1W | HICR6_NFE_WA)); -+ } else { -+ /* Ack pending IRQs */ -+ regmap_write(lpc_snoop->regmap, HICR6, -+ (HICR6_STR_SNP0W | HICR6_STR_SNP1W)); -+ } - - /* Read and save most recent snoop'ed data byte to FIFO */ - regmap_read(lpc_snoop->regmap, SNPWDR, &data); -@@ -182,108 +222,92 @@ - return 0; - } - --static int aspeed_lpc_enable_snoop(struct aspeed_lpc_snoop *lpc_snoop, -- struct device *dev, -- int channel, u16 lpc_port) -+__attribute__((nonnull)) -+static int aspeed_lpc_enable_snoop(struct device *dev, -+ struct aspeed_lpc_snoop *lpc_snoop, -+ struct aspeed_lpc_snoop_channel *channel, -+ const struct aspeed_lpc_snoop_channel_cfg *cfg, -+ u16 lpc_port) - { -- int rc = 0; -- u32 hicr5_en, snpwadr_mask, snpwadr_shift, hicrb_en; -- const struct aspeed_lpc_snoop_model_data *model_data = -- of_device_get_match_data(dev); -+ const struct aspeed_lpc_snoop_model_data *model_data; -+ int rc = 0, id; - -- if (WARN_ON(lpc_snoop->chan[channel].enabled)) -+ if (WARN_ON(channel->enabled)) - return -EBUSY; - -- init_waitqueue_head(&lpc_snoop->chan[channel].wq); -- /* Create FIFO datastructure */ -- rc = kfifo_alloc(&lpc_snoop->chan[channel].fifo, -- SNOOP_FIFO_SIZE, GFP_KERNEL); -+ init_waitqueue_head(&channel->wq); ++ if (get_mmbi_header(chan, &req_data_len, &type, &unread_data_len, &padding) != 0) ++ return; + -+ channel->cfg = cfg; -+ channel->miscdev.minor = MISC_DYNAMIC_MINOR; -+ channel->miscdev.fops = &snoop_fops; -+ channel->miscdev.parent = dev; ++ dev_dbg(chan->dev, "%s: Length: 0x%0x, Protocol Type: %d, Unread data: %d\n", __func__, ++ req_data_len, type, unread_data_len); + -+ id = ida_alloc(&aspeed_lpc_snoop_ida, GFP_KERNEL); -+ if (id < 0) -+ return id; ++ ndev = chan->ndev; + -+ channel->miscdev.name = -+ devm_kasprintf(dev, GFP_KERNEL, "%s%d", DEVICE_NAME, id); -+ if (!channel->miscdev.name) -+ return -ENOMEM; ++ 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; ++ } + -+ rc = kfifo_alloc(&channel->fifo, SNOOP_FIFO_SIZE, GFP_KERNEL); - if (rc) - return rc; - -- lpc_snoop->chan[channel].miscdev.minor = MISC_DYNAMIC_MINOR; -- lpc_snoop->chan[channel].miscdev.name = -- devm_kasprintf(dev, GFP_KERNEL, "%s%d", DEVICE_NAME, channel); -- if (!lpc_snoop->chan[channel].miscdev.name) { -- rc = -ENOMEM; -- goto err_free_fifo; -- } -- lpc_snoop->chan[channel].miscdev.fops = &snoop_fops; -- lpc_snoop->chan[channel].miscdev.parent = dev; -- rc = misc_register(&lpc_snoop->chan[channel].miscdev); -+ rc = misc_register(&channel->miscdev); - if (rc) - goto err_free_fifo; - - /* Enable LPC snoop channel at requested port */ -- switch (channel) { -- case 0: -- hicr5_en = HICR5_EN_SNP0W | HICR5_ENINT_SNP0W; -- snpwadr_mask = SNPWADR_CH0_MASK; -- snpwadr_shift = SNPWADR_CH0_SHIFT; -- hicrb_en = HICRB_ENSNP0D; -- break; -- case 1: -- hicr5_en = HICR5_EN_SNP1W | HICR5_ENINT_SNP1W; -- snpwadr_mask = SNPWADR_CH1_MASK; -- snpwadr_shift = SNPWADR_CH1_SHIFT; -- hicrb_en = HICRB_ENSNP1D; -- break; -- default: -- rc = -EINVAL; -- goto err_misc_deregister; -- } -- -- regmap_update_bits(lpc_snoop->regmap, HICR5, hicr5_en, hicr5_en); -- regmap_update_bits(lpc_snoop->regmap, SNPWADR, snpwadr_mask, -- lpc_port << snpwadr_shift); -- if (model_data->has_hicrb_ensnp) -- regmap_update_bits(lpc_snoop->regmap, HICRB, -- hicrb_en, hicrb_en); -+ regmap_set_bits(lpc_snoop->regmap, HICR5, cfg->hicr5_en); -+ regmap_update_bits(lpc_snoop->regmap, SNPWADR, cfg->snpwadr_mask, -+ lpc_port << cfg->snpwadr_shift); ++ 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); + -+ model_data = of_device_get_match_data(dev); -+ if (model_data && model_data->has_hicrb_ensnp) -+ regmap_set_bits(lpc_snoop->regmap, HICRB, cfg->hicrb_en); - -- lpc_snoop->chan[channel].enabled = true; -+ channel->enabled = true; - - return 0; - --err_misc_deregister: -- misc_deregister(&lpc_snoop->chan[channel].miscdev); - err_free_fifo: -- kfifo_free(&lpc_snoop->chan[channel].fifo); -+ kfifo_free(&channel->fifo); - return rc; - } - -+__attribute__((nonnull)) - static void aspeed_lpc_disable_snoop(struct aspeed_lpc_snoop *lpc_snoop, -- int channel) -+ struct aspeed_lpc_snoop_channel *channel) - { -- if (!lpc_snoop->chan[channel].enabled) -+ if (!channel->enabled) - return; - -- switch (channel) { -- case 0: -- regmap_update_bits(lpc_snoop->regmap, HICR5, -- HICR5_EN_SNP0W | HICR5_ENINT_SNP0W, -- 0); -- break; -- case 1: -- regmap_update_bits(lpc_snoop->regmap, HICR5, -- HICR5_EN_SNP1W | HICR5_ENINT_SNP1W, -- 0); -- break; -- default: -- return; -- } -+ /* Disable interrupts along with the device */ -+ regmap_clear_bits(lpc_snoop->regmap, HICR5, channel->cfg->hicr5_en); - -- lpc_snoop->chan[channel].enabled = false; -+ channel->enabled = false; - /* Consider improving safety wrt concurrent reader(s) */ -- misc_deregister(&lpc_snoop->chan[channel].miscdev); -- kfifo_free(&lpc_snoop->chan[channel].fifo); -+ misc_deregister(&channel->miscdev); -+ kfifo_free(&channel->fifo); ++ 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 void aspeed_lpc_snoop_remove(struct platform_device *pdev) ++static netdev_tx_t mctp_mmbi_tx(struct sk_buff *skb, struct net_device *ndev) +{ -+ struct aspeed_lpc_snoop *lpc_snoop = dev_get_drvdata(&pdev->dev); -+ -+ /* Disable both snoop channels */ -+ aspeed_lpc_disable_snoop(lpc_snoop, &lpc_snoop->chan[0]); -+ aspeed_lpc_disable_snoop(lpc_snoop, &lpc_snoop->chan[1]); - } - - static int aspeed_lpc_snoop_probe(struct platform_device *pdev) - { - struct aspeed_lpc_snoop *lpc_snoop; -- struct device *dev; - struct device_node *np; -- u32 port; -+ struct device *dev; -+ int idx; - int rc; - - dev = &pdev->dev; -@@ -293,77 +317,40 @@ - return -ENOMEM; - - np = pdev->dev.parent->of_node; -- if (!of_device_is_compatible(np, "aspeed,ast2400-lpc-v2") && -- !of_device_is_compatible(np, "aspeed,ast2500-lpc-v2") && -- !of_device_is_compatible(np, "aspeed,ast2600-lpc-v2")) { -- dev_err(dev, "unsupported LPC device binding\n"); -- return -ENODEV; -- } - - lpc_snoop->regmap = syscon_node_to_regmap(np); -- if (IS_ERR(lpc_snoop->regmap)) { -- dev_err(dev, "Couldn't get regmap\n"); -- return -ENODEV; -- } -+ if (IS_ERR(lpc_snoop->regmap)) -+ return dev_err_probe(dev, PTR_ERR(lpc_snoop->regmap), "Couldn't get regmap\n"); - - dev_set_drvdata(&pdev->dev, lpc_snoop); - -- rc = of_property_read_u32_index(dev->of_node, "snoop-ports", 0, &port); -- if (rc) { -- dev_err(dev, "no snoop ports configured\n"); -- return -ENODEV; -- } -- -- lpc_snoop->clk = devm_clk_get(dev, NULL); -- if (IS_ERR(lpc_snoop->clk)) { -- rc = PTR_ERR(lpc_snoop->clk); -- if (rc != -EPROBE_DEFER) -- dev_err(dev, "couldn't get clock\n"); -- return rc; -- } -- rc = clk_prepare_enable(lpc_snoop->clk); -- if (rc) { -- dev_err(dev, "couldn't enable clock\n"); -- return rc; -- } -- - rc = aspeed_lpc_snoop_config_irq(lpc_snoop, pdev); - if (rc) -- goto err; -+ return rc; - -- rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 0, port); -- if (rc) -- goto err; -+ static_assert(ARRAY_SIZE(channel_cfgs) == ARRAY_SIZE(lpc_snoop->chan), -+ "Broken implementation assumption regarding cfg count"); -+ for (idx = ASPEED_LPC_SNOOP_INDEX_0; idx <= ASPEED_LPC_SNOOP_INDEX_MAX; idx++) { -+ u32 port; ++ struct aspeed_mmbi_mctp *mctp = netdev_priv(ndev); ++ int ret; + -+ rc = of_property_read_u32_index(dev->of_node, "snoop-ports", idx, &port); -+ if (rc) -+ break; - -- /* Configuration of 2nd snoop channel port is optional */ -- if (of_property_read_u32_index(dev->of_node, "snoop-ports", -- 1, &port) == 0) { -- rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 1, port); -- if (rc) { -- aspeed_lpc_disable_snoop(lpc_snoop, 0); -- goto err; -- } -+ rc = aspeed_lpc_enable_snoop(dev, lpc_snoop, &lpc_snoop->chan[idx], -+ &channel_cfgs[idx], port); -+ if (rc) -+ goto cleanup_channels; - } - -- return 0; -+ return idx == ASPEED_LPC_SNOOP_INDEX_0 ? -ENODEV : 0; - --err: -- clk_disable_unprepare(lpc_snoop->clk); -+cleanup_channels: -+ aspeed_lpc_snoop_remove(pdev); - - return rc; - } - --static void aspeed_lpc_snoop_remove(struct platform_device *pdev) --{ -- struct aspeed_lpc_snoop *lpc_snoop = dev_get_drvdata(&pdev->dev); -- -- /* Disable both snoop channels */ -- aspeed_lpc_disable_snoop(lpc_snoop, 0); -- aspeed_lpc_disable_snoop(lpc_snoop, 1); -- -- clk_disable_unprepare(lpc_snoop->clk); --} -- - 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 2026-04-08 18:03:48.310705320 +0000 -@@ -0,0 +1,312 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright Aspeed Technology Inc. (C) 2025. All rights reserved -+ */ ++ if (!mmbi_get_bmc_rdy(&mctp->mmbi->chan) || skb->len > MCTP_MMBI_MTU_MAX) { ++ ndev->stats.tx_dropped++; ++ goto out; ++ } + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++ ret = aspeed_mmbi_write(&mctp->mmbi->chan, skb->data, skb->len, MMBI_PROTOCOL_MCTP); ++ if (ret) { ++ netif_stop_queue(ndev); ++ return NETDEV_TX_BUSY; ++ } + -+#define __ASPEED_MBOX_IOCTL_MAGIC 'X' -+#define ASPEED_MBOX_IOCTL_CAPS _IOR(__ASPEED_MBOX_IOCTL_MAGIC, 0, uint32_t[4]) -+#define ASPEED_MBOX_IOCTL_SEND _IOW(__ASPEED_MBOX_IOCTL_MAGIC, 1, uint32_t[8]) -+#define ASPEED_MBOX_IOCTL_RECV _IOR(__ASPEED_MBOX_IOCTL_MAGIC, 2, uint32_t[8]) ++ ndev->stats.tx_packets++; ++ ndev->stats.tx_bytes += skb->len; ++out: ++ kfree_skb(skb); ++ return NETDEV_TX_OK; ++} + -+/** -+ * struct aspeed_mem - Description of a ASPEED memory buffer -+ * @buf: Shared memory base address -+ * @size: Shared memory byte size -+ */ -+struct aspeed_mem { -+ void __iomem *buf; -+ phys_addr_t phys_addr; -+ resource_size_t size; ++static const struct net_device_ops mctp_mmbi_netdev_ops = { ++ .ndo_start_xmit = mctp_mmbi_tx, +}; + -+/* -+ * Message prototype of IPC. It should be defined per your usage. -+ * cmd: type of message -+ * len: length of message -+ */ -+struct ast_mbox_msg { -+ u32 cmd; -+ u32 len; -+}; ++static void aspeed_mctp_mmbi_setup(struct net_device *ndev) ++{ ++ ndev->type = ARPHRD_MCTP; + -+/* -+ * struct ast_mbox_chan - Description of a ASPEED mailbox channel -+ * @cl: Mailbox client -+ * @mdev: Misc device -+ * @chan: Mailbox channel -+ * @tx_base: Information of tx shmem -+ * @rx_base: Information of rx shmem -+ * @rx_buffer: buffer to store data on callback -+ * @rx_wait: Wait queue for receiving messages -+ * @rx_msg_lock: Spinlock to protect rx_buffer -+ */ -+struct ast_mbox_info { -+ struct device *dev; -+ struct mbox_client cl; -+ struct miscdevice mdev; -+ struct mbox_chan *chan; -+ struct aspeed_mem tx_base; -+ struct aspeed_mem rx_base; -+ char *rx_buffer; -+ wait_queue_head_t rx_wait; -+ spinlock_t rx_msg_lock; /* spinlock to protect rx_buffer */ -+}; ++ /* 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; + -+static ssize_t mbox_read(struct file *fp, char __user *buf, size_t nbytes, loff_t *off) ++ 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 ast_mbox_info *info = container_of(fp->private_data, struct ast_mbox_info, mdev); ++ struct aspeed_mmbi_mctp *mctp; ++ struct net_device *ndev; ++ char name[32]; + int ret; + -+ if (nbytes == 0) -+ return 0; ++ 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; + -+ if (!info->rx_base.buf) { -+ dev_err(info->dev, "No RX shmem\n"); ++ 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); ++} ++ ++static int aspeed_pci_bmc_dev_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ struct aspeed_pci_bmc_dev *pci_bmc_dev = 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 + vsize > pci_bmc_dev->mem_bar_base + 0x100000) + return -EINVAL; -+ } + -+ if (nbytes > info->rx_base.size) { -+ dev_warn(info->dev, "Read size %zu exceeds RX shmem size %llu\n", -+ nbytes, info->rx_base.size); -+ nbytes = info->rx_base.size; -+ } ++ prot = pgprot_noncached(prot); + -+ ret = copy_to_user((void __user *)buf, info->rx_base.buf, nbytes); -+ if (ret) -+ return -EFAULT; ++ if (remap_pfn_range(vma, vma->vm_start, ++ (pci_bmc_dev->mem_bar_base >> PAGE_SHIFT) + vma->vm_pgoff, ++ vsize, prot)) ++ return -EAGAIN; + -+ return nbytes; ++ return 0; +} + -+static ssize_t mbox_write(struct file *fp, const char *buf, size_t nbytes, loff_t *off) ++static const struct file_operations aspeed_pci_bmc_dev_fops = { ++ .owner = THIS_MODULE, ++ .mmap = aspeed_pci_bmc_dev_mmap, ++}; ++ ++static ssize_t aspeed_queue_rx(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, ++ char *buf, loff_t off, size_t count) +{ -+ struct ast_mbox_info *info = container_of(fp->private_data, struct ast_mbox_info, mdev); ++ struct aspeed_queue_message *queue = attr->private; ++ struct aspeed_pci_bmc_dev *pci_bmc_device = queue->pci_bmc_device; ++ int index = queue->index; ++ u32 *data = (u32 *)buf; + int ret; + -+ if (nbytes == 0) -+ return 0; ++ ret = wait_event_interruptible(queue->rx_wait, ++ !(readl(pci_bmc_device->msg_bar_reg + PCI_BMC_BMC2HOST_STS) & ++ ((index == QUEUE1) ? BMC2HOST_Q1_EMPTY : BMC2HOST_Q2_EMPTY))); ++ if (ret) ++ return -EINTR; + -+ if (!info->tx_base.buf) { -+ dev_err(info->dev, "No TX shmem\n"); -+ return -EINVAL; -+ } ++ data[0] = readl(pci_bmc_device->msg_bar_reg + ++ ((index == QUEUE1) ? PCI_BMC_BMC2HOST_Q1 : PCI_BMC_BMC2HOST_Q2)); + -+ if (nbytes > info->tx_base.size) { -+ dev_warn(info->dev, "Write size %zu exceeds TX shmem size %llu\n", -+ nbytes, info->tx_base.size); -+ nbytes = info->tx_base.size; -+ } ++ writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, ++ pci_bmc_device->msg_bar_reg + PCI_BMC_HOST2BMC_STS); + -+ ret = copy_from_user(info->tx_base.buf, (void __user *)buf, nbytes); ++ return sizeof(u32); ++} ++ ++static ssize_t aspeed_queue_tx(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, ++ char *buf, loff_t off, size_t count) ++{ ++ struct aspeed_queue_message *queue = attr->private; ++ struct aspeed_pci_bmc_dev *pci_bmc_device = queue->pci_bmc_device; ++ int index = queue->index; ++ u32 tx_buff; ++ int ret; ++ ++ if (count != sizeof(u32)) ++ return -EINVAL; ++ ++ ret = wait_event_interruptible(queue->tx_wait, ++ !(readl(pci_bmc_device->msg_bar_reg + PCI_BMC_HOST2BMC_STS) & ++ ((index == QUEUE1) ? HOST2BMC_Q1_FULL : HOST2BMC_Q2_FULL))); + if (ret) -+ return -EFAULT; ++ return -EINTR; + -+ return nbytes; ++ memcpy(&tx_buff, buf, 4); ++ writel(tx_buff, pci_bmc_device->msg_bar_reg + ++ ((index == QUEUE1) ? PCI_BMC_HOST2BMC_Q1 : PCI_BMC_HOST2BMC_Q2)); ++ //trigger to host ++ writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, ++ pci_bmc_device->msg_bar_reg + PCI_BMC_HOST2BMC_STS); ++ ++ return sizeof(u32); +} + -+static __poll_t mbox_poll(struct file *fp, struct poll_table_struct *wait) ++static irqreturn_t aspeed_pci_host_bmc_device_interrupt(int irq, void *dev_id) +{ -+ struct ast_mbox_info *info = container_of(fp->private_data, struct ast_mbox_info, mdev); -+ __poll_t mask = 0; ++ struct aspeed_pci_bmc_dev *pci_bmc_device = dev_id; ++ u32 bmc2host_q_sts = readl(pci_bmc_device->msg_bar_reg + PCI_BMC_BMC2HOST_STS); + -+ poll_wait(fp, &info->rx_wait, wait); ++ if (bmc2host_q_sts & BMC2HOST_INT_STS_DOORBELL) ++ writel(BMC2HOST_INT_STS_DOORBELL, ++ pci_bmc_device->msg_bar_reg + PCI_BMC_BMC2HOST_STS); + -+ if (info->rx_buffer) -+ mask |= POLLIN | POLLRDNORM; ++ if (bmc2host_q_sts & BMC2HOST_ENABLE_INTB) ++ writel(BMC2HOST_ENABLE_INTB, pci_bmc_device->msg_bar_reg + PCI_BMC_BMC2HOST_STS); + -+ return mask; ++ if (bmc2host_q_sts & BMC2HOST_Q1_FULL) ++ dev_info(pci_bmc_device->dev, "Q1 Full\n"); ++ ++ if (bmc2host_q_sts & BMC2HOST_Q2_FULL) ++ dev_info(pci_bmc_device->dev, "Q2 Full\n"); ++ ++ //check q1 ++ if (!(readl(pci_bmc_device->msg_bar_reg + PCI_BMC_HOST2BMC_STS) & HOST2BMC_Q1_FULL)) ++ wake_up_interruptible(&pci_bmc_device->queue[QUEUE1].tx_wait); ++ ++ if (!(readl(pci_bmc_device->msg_bar_reg + PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q1_EMPTY)) ++ wake_up_interruptible(&pci_bmc_device->queue[QUEUE1].rx_wait); ++ //chech q2 ++ if (!(readl(pci_bmc_device->msg_bar_reg + PCI_BMC_HOST2BMC_STS) & HOST2BMC_Q2_FULL)) ++ wake_up_interruptible(&pci_bmc_device->queue[QUEUE2].tx_wait); ++ ++ if (!(readl(pci_bmc_device->msg_bar_reg + PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q2_EMPTY)) ++ wake_up_interruptible(&pci_bmc_device->queue[QUEUE2].rx_wait); ++ ++ return IRQ_HANDLED; +} + -+static long mbox_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) ++static irqreturn_t aspeed_pci_host_mbox_interrupt(int irq, void *dev_id) +{ -+ struct ast_mbox_info *info = container_of(fp->private_data, struct ast_mbox_info, mdev); -+ u32 *data; -+ u32 msg[8]; -+ unsigned long flags; -+ int ret = 0; ++ struct aspeed_pci_bmc_dev *pci_bmc_device = dev_id; ++ u32 isr = readl(pci_bmc_device->sio_mbox_reg + 0x94); + -+ switch (cmd) { -+ case ASPEED_MBOX_IOCTL_CAPS: -+ data = (u32 *)arg; -+ data[0] = (info->tx_base.phys_addr) >> 8; -+ data[1] = info->tx_base.size; -+ data[2] = (info->rx_base.phys_addr) >> 8; -+ data[3] = info->rx_base.size; -+ break; -+ case ASPEED_MBOX_IOCTL_SEND: -+ ret = copy_from_user(msg, (void __user *)arg, sizeof(msg)); -+ if (ret) { -+ dev_dbg(info->dev, "Failed to copy message from user\n"); -+ return -EFAULT; -+ } ++ if (isr & BIT(7)) ++ writel(BIT(7), pci_bmc_device->sio_mbox_reg + 0x94); + -+ ret = mbox_send_message(info->chan, msg); -+ if (ret < 0) -+ dev_dbg(info->dev, "Failed to send message via mailbox\n"); -+ break; -+ case ASPEED_MBOX_IOCTL_RECV: -+ spin_lock_irqsave(&info->rx_msg_lock, flags); -+ if (!info->rx_buffer) { -+ spin_unlock_irqrestore(&info->rx_msg_lock, flags); -+ dev_dbg(info->dev, "No message received\n"); -+ return -EAGAIN; -+ } -+ ret = copy_to_user((void __user *)arg, info->rx_buffer, sizeof(msg)); -+ info->rx_buffer = NULL; -+ spin_unlock_irqrestore(&info->rx_msg_lock, flags); -+ if (ret) { -+ dev_dbg(info->dev, "Failed to copy message to user\n"); -+ return -EFAULT; -+ } -+ break; -+ default: -+ dev_err(info->dev, "Unsupported cmd: %x\n", cmd); -+ ret = -EINVAL; ++ 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); + } + -+ return ret; ++ if (get_mmbi_header(chan, &req_data_len, &type, &unread_data_len, &padding) != 0) ++ queue_work(system_unbound_wq, &chan->work); +} + -+static const struct file_operations aspeed_mbox_fops = { -+ .owner = THIS_MODULE, -+ .read = mbox_read, -+ .write = mbox_write, -+ .poll = mbox_poll, -+ .unlocked_ioctl = mbox_ioctl, -+}; ++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; + -+static void mbox_rx_callback(struct mbox_client *client, void *message) ++ 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 ast_mbox_info *info = container_of(client, struct ast_mbox_info, cl); -+ unsigned long flags; ++ struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); + -+ spin_lock_irqsave(&info->rx_msg_lock, flags); -+ info->rx_buffer = message; -+ spin_unlock_irqrestore(&info->rx_msg_lock, flags); ++ /* 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; ++ } ++ } else { ++ pci_bmc_dev->msi_idx_table = ast2600_msi_idx_table; ++ } + -+ wake_up_interruptible(&info->rx_wait); ++ if (pci_alloc_irq_vectors(pdev, 1, BMC_MULTI_MSI, PCI_IRQ_INTX | PCI_IRQ_MSI) <= 1) ++ /* Set all msi index to the first vector */ ++ memset(pci_bmc_dev->msi_idx_table, 0, sizeof(int) * MAX_MSI_NUM); +} + -+static int aspeed_mbox_probe(struct platform_device *pdev) ++static int aspeed_pci_bmc_device_setup_queue(struct pci_dev *pdev) +{ -+ struct ast_mbox_info *info; -+ struct resource *res; ++ struct aspeed_pci_bmc_dev *pci_bmc_device = pci_get_drvdata(pdev); + struct device *dev = &pdev->dev; -+ int ret; -+ u32 tx_tout = -1; -+ -+ info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); -+ if (!info) -+ return -ENOMEM; -+ -+ info->tx_base.buf = devm_platform_get_and_ioremap_resource(pdev, 0, &res); -+ if (PTR_ERR(info->tx_base.buf) == -EBUSY) { -+ /* if reserved area in SRAM, try just ioremap */ -+ info->tx_base.size = resource_size(res); -+ info->tx_base.buf = devm_ioremap(dev, res->start, info->tx_base.size); -+ } -+ if (IS_ERR(info->tx_base.buf)) { -+ info->tx_base.buf = NULL; -+ } else { -+ info->tx_base.phys_addr = res->start; -+ info->tx_base.size = resource_size(res); -+ } ++ int ret, i; + -+ info->rx_base.buf = devm_platform_get_and_ioremap_resource(pdev, 1, &res); -+ if (PTR_ERR(info->rx_base.buf) == -EBUSY) { -+ /* if reserved area in SRAM, try just ioremap */ -+ info->rx_base.size = resource_size(res); -+ info->rx_base.buf = devm_ioremap(dev, res->start, info->rx_base.size); -+ } -+ if (IS_ERR(info->rx_base.buf)) { -+ info->rx_base = info->tx_base; -+ } else { -+ info->rx_base.phys_addr = res->start; -+ info->rx_base.size = resource_size(res); -+ } ++ for (i = 0; i < ASPEED_QUEUE_NUM; i++) { ++ struct aspeed_queue_message *queue = &pci_bmc_device->queue[i]; + -+ if (device_property_read_u32(dev, "aspeed,tx-timeout", &tx_tout)) -+ tx_tout = -1; ++ init_waitqueue_head(&queue->tx_wait); ++ init_waitqueue_head(&queue->rx_wait); + -+ dev_info(dev, "TX shmem: phys 0x%pa size %llu\n", -+ &info->tx_base.phys_addr, info->tx_base.size); -+ dev_info(dev, "RX shmem: phys 0x%pa size %llu\n", -+ &info->rx_base.phys_addr, info->rx_base.size); -+ dev_info(dev, "TX timeout: %u ms\n", tx_tout); ++ sysfs_bin_attr_init(&queue->bin); + -+ info->cl.dev = dev; -+ info->cl.rx_callback = mbox_rx_callback; -+ info->cl.tx_block = true; -+ info->cl.knows_txdone = false; -+ info->cl.tx_tout = tx_tout; ++ /* Queue name index starts from 1 */ ++ queue->bin.attr.name = ++ devm_kasprintf(dev, GFP_KERNEL, "pci-bmc-dev-queue%d", (i + 1)); ++ queue->bin.attr.mode = 0600; ++ queue->bin.read = aspeed_queue_rx; ++ queue->bin.write = aspeed_queue_tx; ++ queue->bin.size = 4; ++ queue->bin.private = queue; + -+ info->chan = mbox_request_channel(&info->cl, 0); -+ if (IS_ERR(info->chan)) { -+ dev_err(dev, "failed to request channel err %ld\n", -+ PTR_ERR(info->chan)); -+ return -EPROBE_DEFER; -+ } ++ ret = sysfs_create_bin_file(&pdev->dev.kobj, &queue->bin); ++ if (ret) { ++ dev_err(dev, "error for bin%d file\n", i); ++ return ret; ++ } + -+ info->rx_buffer = NULL; -+ init_waitqueue_head(&info->rx_wait); -+ spin_lock_init(&info->rx_msg_lock); -+ info->dev = dev; -+ platform_set_drvdata(pdev, info); ++ queue->kn = kernfs_find_and_get(dev->kobj.sd, queue->bin.attr.name); ++ if (!queue->kn) { ++ sysfs_remove_bin_file(&dev->kobj, &queue->bin); ++ return ret; ++ } + -+ info->mdev.parent = dev; -+ info->mdev.minor = MISC_DYNAMIC_MINOR; -+ info->mdev.name = dev_name(dev); -+ info->mdev.fops = &aspeed_mbox_fops; -+ ret = misc_register(&info->mdev); -+ if (ret) { -+ dev_err(dev, "failed to register misc device\n"); -+ return ret; ++ queue->index = i; ++ queue->pci_bmc_device = pci_bmc_device; + } + + return 0; +} + -+static void aspeed_mbox_remove(struct platform_device *pdev) ++static int aspeed_pci_bmc_device_setup_vuart(struct pci_dev *pdev) +{ -+ struct ast_mbox_info *info = platform_get_drvdata(pdev); ++ struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); ++ struct device *dev = &pdev->dev; ++ u16 vuart_ioport; ++ int ret, i; + -+ mbox_free_channel(info->chan); -+ misc_deregister(&info->mdev); ++ for (i = 0; i < VUART_MAX_PARMS; i++) { ++ /* Assign the line to non-exist device */ ++ pci_bmc_dev->uart_line[i] = -ENOENT; ++ vuart_ioport = 0x3F8 - (i * 0x100); ++ pci_bmc_dev->uart[i].port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; ++ pci_bmc_dev->uart[i].port.uartclk = 115200 * 16; ++ pci_bmc_dev->uart[i].port.irq = ++ pci_irq_vector(pdev, pci_bmc_dev->msi_idx_table[VUART0_MSI + i]); ++ pci_bmc_dev->uart[i].port.dev = dev; ++ pci_bmc_dev->uart[i].port.iotype = UPIO_MEM32; ++ pci_bmc_dev->uart[i].port.iobase = 0; ++ pci_bmc_dev->uart[i].port.mapbase = ++ pci_bmc_dev->message_bar_base + (vuart_ioport << 2); ++ pci_bmc_dev->uart[i].port.membase = 0; ++ pci_bmc_dev->uart[i].port.type = PORT_16550A; ++ pci_bmc_dev->uart[i].port.flags |= (UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE); ++ pci_bmc_dev->uart[i].port.regshift = 2; ++ ret = serial8250_register_8250_port(&pci_bmc_dev->uart[i]); ++ if (ret < 0) { ++ dev_err_probe(dev, ret, "Can't setup PCIe VUART\n"); ++ return ret; ++ } ++ pci_bmc_dev->uart_line[i] = ret; ++ } ++ return 0; +} + -+static const struct of_device_id mbox_cl_match[] = { -+ { .compatible = "aspeed,aspeed-mbox" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, mbox_cl_match); ++static int aspeed_pci_bmc_device_setup_memory_mapping(struct pci_dev *pdev) ++{ ++ struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); ++ struct device *dev = &pdev->dev; ++ int ret; + -+static struct platform_driver aspeed_mbox_driver = { -+ .driver = { -+ .name = "aspeed_mbox_client", -+ .of_match_table = mbox_cl_match, -+ }, -+ .probe = aspeed_mbox_probe, -+ .remove = aspeed_mbox_remove, -+}; -+module_platform_driver(aspeed_mbox_driver); ++ pci_bmc_dev->miscdev.minor = MISC_DYNAMIC_MINOR; ++ pci_bmc_dev->miscdev.name = ++ devm_kasprintf(dev, GFP_KERNEL, "%s%d", DRIVER_NAME, pci_bmc_dev->id); ++ pci_bmc_dev->miscdev.fops = &aspeed_pci_bmc_dev_fops; ++ pci_bmc_dev->miscdev.parent = dev; + -+MODULE_AUTHOR("Jammy Huang "); -+MODULE_DESCRIPTION("ASPEED MBOX CLIENT driver"); -+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 2026-04-08 18:03:48.310705320 +0000 -@@ -0,0 +1,2658 @@ -+// SPDX-License-Identifier: GPL-2.0 -+// Copyright (c) 2020, Intel Corporation. ++ ret = misc_register(&pci_bmc_dev->miscdev); ++ if (ret) { ++ pr_err("host bmc register fail %d\n", ret); ++ return ret; ++ } + -+#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 ++ return 0; ++} + -+#include ++static int aspeed_pci_bmc_device_setup_mbox(struct pci_dev *pdev) ++{ ++ struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); ++ struct device *dev = &pdev->dev; ++ int ret; + -+/* AST2600 MCTP Controller registers */ -+#define ASPEED_MCTP_CTRL 0x000 -+#define TX_CMD_TRIGGER BIT(0) -+#define RX_CMD_READY BIT(4) -+#define MATCHING_EID BIT(9) ++ /* setup mbox */ ++ pci_bmc_dev->pcie_sio_decode_addr = pci_bmc_dev->msg_bar_reg + PCIE_DEVICE_SIO_ADDR; ++ writel(0xaa, pci_bmc_dev->pcie_sio_decode_addr); ++ writel(0xa5, pci_bmc_dev->pcie_sio_decode_addr); ++ writel(0xa5, pci_bmc_dev->pcie_sio_decode_addr); ++ writel(0x07, pci_bmc_dev->pcie_sio_decode_addr); ++ writel(0x0e, pci_bmc_dev->pcie_sio_decode_addr + 0x04); ++ /* disable */ ++ writel(0x30, pci_bmc_dev->pcie_sio_decode_addr); ++ writel(0x00, pci_bmc_dev->pcie_sio_decode_addr + 0x04); ++ /* set decode address 0x100 */ ++ writel(0x60, pci_bmc_dev->pcie_sio_decode_addr); ++ writel(0x01, pci_bmc_dev->pcie_sio_decode_addr + 0x04); ++ writel(0x61, pci_bmc_dev->pcie_sio_decode_addr); ++ writel(0x00, pci_bmc_dev->pcie_sio_decode_addr + 0x04); ++ /* enable */ ++ writel(0x30, pci_bmc_dev->pcie_sio_decode_addr); ++ writel(0x01, pci_bmc_dev->pcie_sio_decode_addr + 0x04); ++ pci_bmc_dev->sio_mbox_reg = pci_bmc_dev->msg_bar_reg + 0x400; + -+#define ASPEED_MCTP_TX_CMD 0x004 -+#define ASPEED_MCTP_RX_CMD 0x008 ++ ret = devm_request_irq(dev, ++ pci_irq_vector(pdev, pci_bmc_dev->msi_idx_table[MBX_MSI]), ++ aspeed_pci_host_mbox_interrupt, IRQF_SHARED, ++ devm_kasprintf(dev, GFP_KERNEL, "aspeed-sio-mbox%d", pci_bmc_dev->id), ++ pci_bmc_dev); ++ if (ret) { ++ pr_err("host bmc device Unable to get IRQ %d\n", ret); ++ return ret; ++ } + -+#define ASPEED_MCTP_INT_STS 0x00c -+#define ASPEED_MCTP_INT_EN 0x010 -+#define TX_CMD_SENT_INT BIT(0) -+#define TX_CMD_LAST_INT BIT(1) -+#define TX_CMD_WRONG_INT BIT(2) -+#define RX_CMD_RECEIVE_INT BIT(8) -+#define RX_CMD_NO_MORE_INT BIT(9) ++ return 0; ++} + -+#define ASPEED_MCTP_EID 0x014 -+#define MEMORY_SPACE_MAPPING GENMASK(31, 28) -+#define MCTP_EID GENMASK(7, 0) -+#define ASPEED_MCTP_OBFF_CTRL 0x018 ++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); + -+#define ASPEED_MCTP_ENGINE_CTRL 0x01c -+#define TX_MAX_PAYLOAD_SIZE_SHIFT 0 -+#define TX_MAX_PAYLOAD_SIZE_MASK GENMASK(1, TX_MAX_PAYLOAD_SIZE_SHIFT) -+#define TX_MAX_PAYLOAD_SIZE(x) \ -+ (((x) << TX_MAX_PAYLOAD_SIZE_SHIFT) & TX_MAX_PAYLOAD_SIZE_MASK) -+#define RX_MAX_PAYLOAD_SIZE_SHIFT 4 -+#define RX_MAX_PAYLOAD_SIZE_MASK GENMASK(5, RX_MAX_PAYLOAD_SIZE_SHIFT) -+#define RX_MAX_PAYLOAD_SIZE(x) \ -+ (((x) << RX_MAX_PAYLOAD_SIZE_SHIFT) & RX_MAX_PAYLOAD_SIZE_MASK) -+#define FIFO_LAYOUT_SHIFT 8 -+#define FIFO_LAYOUT_MASK GENMASK(9, FIFO_LAYOUT_SHIFT) -+#define FIFO_LAYOUT(x) \ -+ (((x) << FIFO_LAYOUT_SHIFT) & FIFO_LAYOUT_MASK) ++ 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; ++} + -+#define ASPEED_MCTP_RX_BUF_ADDR 0x08 -+#define ASPEED_MCTP_RX_BUF_HI_ADDR 0x020 -+#define ASPEED_MCTP_RX_BUF_SIZE 0x024 -+#define ASPEED_MCTP_RX_BUF_RD_PTR 0x028 -+#define UPDATE_RX_RD_PTR BIT(31) -+#define RX_BUF_RD_PTR_MASK GENMASK(11, 0) -+#define ASPEED_MCTP_RX_BUF_WR_PTR 0x02c -+#define RX_BUF_WR_PTR_MASK GENMASK(11, 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; + -+#define ASPEED_MCTP_TX_BUF_ADDR 0x04 -+#define ASPEED_MCTP_TX_BUF_HI_ADDR 0x030 -+#define ASPEED_MCTP_TX_BUF_SIZE 0x034 -+#define ASPEED_MCTP_TX_BUF_RD_PTR 0x038 -+#define UPDATE_TX_RD_PTR BIT(31) -+#define TX_BUF_RD_PTR_MASK GENMASK(11, 0) -+#define ASPEED_MCTP_TX_BUF_WR_PTR 0x03c -+#define TX_BUF_WR_PTR_MASK GENMASK(11, 0) -+#define ASPEED_G7_MCTP_PCIE_BDF 0x04c ++ /* First, check mmbi signature "#MMBI$" */ ++ ret = mmbi_signature_check(chan); ++ if (ret) { ++ dev_warn(dev, "Check MMBI signature timeout\n"); ++ return ret; ++ } + -+#define ADDR_LEN GENMASK(26, 0) -+#define DATA_ADDR(x) (((x) >> 4) & ADDR_LEN) ++ memcpy_fromio(&desc, chan->desc_vmem, sizeof(desc)); + -+/* TX command */ -+#define TX_LAST_CMD BIT(31) -+#define TX_DATA_ADDR_SHIFT 4 -+#define TX_DATA_ADDR_MASK GENMASK(30, TX_DATA_ADDR_SHIFT) -+#define TX_DATA_ADDR(x) \ -+ ((DATA_ADDR(x) << TX_DATA_ADDR_SHIFT) & TX_DATA_ADDR_MASK) -+#define TX_RESERVED_1_MASK GENMASK(1, 0) /* must be 1 */ -+#define TX_RESERVED_1 1 -+#define TX_STOP_AFTER_CMD BIT(16) -+#define TX_INTERRUPT_AFTER_CMD BIT(15) -+#define TX_PACKET_SIZE_SHIFT 2 -+#define TX_PACKET_SIZE_MASK GENMASK(12, TX_PACKET_SIZE_SHIFT) -+#define TX_PACKET_SIZE(x) \ -+ (((x) << TX_PACKET_SIZE_SHIFT) & TX_PACKET_SIZE_MASK) -+#define TX_RESERVED_0_MASK GENMASK(1, 0) /* MBZ */ -+#define TX_RESERVED_0 0 ++ /* 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); + -+/* RX command */ -+#define RX_INTERRUPT_AFTER_CMD BIT(2) -+#define RX_DATA_ADDR_SHIFT 4 -+#define RX_DATA_ADDR_MASK GENMASK(30, RX_DATA_ADDR_SHIFT) -+#define RX_DATA_ADDR(x) \ -+ ((DATA_ADDR(x) << RX_DATA_ADDR_SHIFT) & RX_DATA_ADDR_MASK) ++ /* 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); + -+#define ADDR_LEN_2500 GENMASK(23, 0) -+#define DATA_ADDR_2500(x) (((x) >> 7) & ADDR_LEN_2500) ++ ret = mmbi_bmc_up_check(chan); ++ if (ret) { ++ dev_warn(dev, "Check BMC up timeout\n"); ++ return ret; ++ } + -+/* TX command for ast2500 */ -+#define TX_DATA_ADDR_MASK_2500 GENMASK(30, 8) -+#define TX_DATA_ADDR_2500(x) \ -+ FIELD_PREP(TX_DATA_ADDR_MASK_2500, DATA_ADDR_2500(x)) -+#define TX_PACKET_SIZE_2500(x) \ -+ FIELD_PREP(GENMASK(11, 2), x) -+#define TX_PACKET_DEST_EID GENMASK(7, 0) -+#define TX_PACKET_TARGET_ID GENMASK(31, 16) -+#define TX_PACKET_ROUTING_TYPE BIT(14) -+#define TX_PACKET_TAG_OWNER BIT(13) -+#define TX_PACKET_PADDING_LEN GENMASK(1, 0) ++ /* 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; ++ } + -+/* Rx command for ast2500 */ -+#define RX_LAST_CMD BIT(31) -+#define RX_DATA_ADDR_MASK_2500 GENMASK(29, 7) -+#define RX_DATA_ADDR_2500(x) \ -+ FIELD_PREP(RX_DATA_ADDR_MASK_2500, DATA_ADDR_2500(x)) -+#define RX_PACKET_SIZE GENMASK(30, 24) -+#define RX_PACKET_SRC_EID GENMASK(23, 16) -+#define RX_PACKET_ROUTING_TYPE GENMASK(15, 14) -+#define RX_PACKET_TAG_OWNER BIT(13) -+#define RX_PACKET_SEQ_NUMBER GENMASK(12, 11) -+#define RX_PACKET_MSG_TAG GENMASK(10, 8) -+#define RX_PACKET_SOM BIT(7) -+#define RX_PACKET_EOM BIT(6) -+#define RX_PACKET_PADDING_LEN GENMASK(5, 4) ++ /* 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; ++ } + -+/* HW buffer sizes */ -+#define TX_PACKET_COUNT 48 -+#define RX_PACKET_COUNT 96 -+#if (RX_PACKET_COUNT % 4 != 0) -+#error The Rx buffer size should be 4-aligned. -+#error 1.Make runaway wrap boundary can be determined in Ast2600 A1/A2. -+#error 2.Fix the runaway read pointer bug in Ast2600 A3. -+#endif -+#define TX_MAX_PACKET_COUNT (TX_BUF_RD_PTR_MASK + 1) -+#define RX_MAX_PACKET_COUNT (RX_BUF_RD_PTR_MASK + 1) ++ /* 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; ++ } + -+/* Per client packet cache sizes */ -+#define RX_RING_COUNT 64 -+#define TX_RING_COUNT 64 ++ /* 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; + -+/* PCIe Host Controller registers */ -+#define ASPEED_PCIE_LINK 0x0c0 -+#define PCIE_LINK_STS BIT(5) -+#define ASPEED_PCIE_MISC_STS_1 0x0c4 ++ /* 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; + -+/* PCIe Host Controller registers */ -+#define ASPEED_G7_PCIE_LOCATE 0x300 -+#define PCIE_LOCATE_IO BIT(0) -+#define ASPEED_G7_PCIE_LINK 0x358 -+#define PCIE_G7_LINK_STS BIT(8) -+#define ASPEED_G7_IO_PCIE_LINK 0x344 -+#define PCIE_G7_IO_LINK_STS BIT(18) ++ 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); + -+/* PCI address definitions */ -+#define PCI_DEV_NUM_MASK GENMASK(4, 0) -+#define PCI_BUS_NUM_SHIFT 5 -+#define PCI_BUS_NUM_MASK GENMASK(12, PCI_BUS_NUM_SHIFT) -+#define GET_PCI_DEV_NUM(x) ((x) & PCI_DEV_NUM_MASK) -+#define GET_PCI_BUS_NUM(x) (((x) & PCI_BUS_NUM_MASK) >> PCI_BUS_NUM_SHIFT) ++ 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); + -+/* MCTP header definitions */ -+#define MCTP_HDR_SRC_EID_OFFSET 14 -+#define MCTP_HDR_TAG_OFFSET 15 -+#define MCTP_HDR_SOM BIT(7) -+#define MCTP_HDR_EOM BIT(6) -+#define MCTP_HDR_SOM_EOM (MCTP_HDR_SOM | MCTP_HDR_EOM) -+#define MCTP_PAYLOAD_TYPE_OFFSET 0 -+#define MCTP_HDR_TYPE_CONTROL 0 -+#define MCTP_HDR_TYPE_VDM_PCI 0x7e -+#define MCTP_HDR_TYPE_SPDM 0x5 -+#define MCTP_HDR_TYPE_BASE_LAST MCTP_HDR_TYPE_SPDM -+#define MCTP_PAYLOAD_VENDOR_OFFSET 1 -+#define MCTP_PAYLOAD_VDM_TYPE_OFFSET 3 ++ /* 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; ++ } + -+/* MCTP header DW little endian mask definitions */ -+/* 0th DW */ -+#define MCTP_HDR_DW_LE_ROUTING_TYPE GENMASK(26, 24) -+#define MCTP_HDR_DW_LE_PACKET_SIZE GENMASK(9, 0) -+/* 1st DW */ -+#define MCTP_HDR_DW_LE_PADDING_LEN GENMASK(13, 12) -+/* 2nd DW */ -+#define MCTP_HDR_DW_LE_TARGET_ID GENMASK(31, 16) -+/* 3rd DW */ -+#define MCTP_HDR_DW_LE_TAG_OWNER BIT(3) -+#define MCTP_HDR_DW_LE_DEST_EID GENMASK(23, 16) ++ /* 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; ++ } ++ } + -+#define ASPEED_MCTP_2600 0 -+#define ASPEED_MCTP_2600A3 1 ++ INIT_WORK(&chan->work, aspeed_mmbi_work_func); + -+#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 ++ return 0; ++err_mismatch: ++ /* Change state to INIT_MISMATCH */ ++ mmbi_set_host_rst(chan, 1); ++ return -EINVAL; ++} + -+#define ASPEED_G7_SCU_PCIE0_CTRL_OFFSET 0xa60 -+#define ASPEED_G7_SCU_PCIE1_CTRL_OFFSET 0xae0 -+#define ASPEED_G7_SCU_PCIE_CTRL_VDM_EN BIT(1) ++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; + -+struct aspeed_mctp_match_data { -+ u32 rx_cmd_size; -+ u32 tx_cmd_size; -+ u32 packet_unit_size; -+ bool need_address_mapping; -+ bool vdm_hdr_direct_xfer; -+ bool fifo_auto_surround; -+ bool dma_need_64bits_width; -+ u32 scu_pcie_ctrl_offset; -+}; ++ chan->desc_vmem = mmbi->mem; ++ chan->mmbi = mmbi; + -+struct aspeed_mctp_rx_cmd { -+ u32 rx_lo; -+ u32 rx_hi; -+}; ++ ret = mmbi_desc_init(chan); ++ if (ret) { ++ dev_err(dev, "Unable to init mmbi desc\n"); ++ return ret; ++ } + -+struct aspeed_mctp_tx_cmd { -+ u32 tx_lo; -+ u32 tx_hi; -+}; ++ /* Initialize MTCP function */ ++ ret = aspeed_mmbi_mctp_init(chan); ++ if (ret) { ++ dev_err(dev, "Unable to init mctp\n"); ++ return ret; ++ } + -+struct aspeed_g7_mctp_tx_cmd { -+ u32 tx_lo; -+ u32 tx_mid; -+ u32 tx_hi; -+ u32 reserved; -+}; ++ /* 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); + -+struct mctp_buffer { -+ void *vaddr; -+ dma_addr_t dma_handle; -+}; ++ return 0; ++} + -+struct mctp_channel { -+ struct mctp_buffer data; -+ struct mctp_buffer cmd; -+ struct tasklet_struct tasklet; -+ u32 buffer_count; -+ u32 rd_ptr; -+ u32 wr_ptr; -+ bool stopped; -+}; ++/* 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; + -+struct aspeed_mctp { -+ struct device *dev; -+ struct miscdevice mctp_miscdev; -+ const struct aspeed_mctp_match_data *match_data; -+ struct regmap *map; -+ struct reset_control *reset; -+ /* -+ * The reset of the dma block in the MCTP-RC is connected to -+ * another reset pin. -+ */ -+ struct reset_control *reset_dma; -+ struct mctp_channel tx; -+ struct mctp_channel rx; -+ struct list_head clients; -+ struct mctp_client *default_client; -+ struct list_head mctp_type_handlers; -+ /* -+ * clients_lock protects list of clients, list of type handlers -+ * and default client -+ */ -+ spinlock_t clients_lock; -+ struct list_head endpoints; -+ size_t endpoints_count; -+ /* -+ * endpoints_lock protects list of endpoints -+ */ -+ struct mutex endpoints_lock; -+ struct { -+ struct regmap *map; -+ struct delayed_work rst_dwork; -+ bool need_uevent; -+ } pcie; -+ struct { -+ bool enable; -+ bool first_loop; -+ int packet_counter; -+ } rx_runaway_wa; -+ bool rx_warmup; -+ u8 eid; -+ struct platform_device *peci_mctp; -+ /* Use the flag to identify RC or EP */ -+ bool rc_f; -+ /* Use the flag to identify the support of MCTP interrupt */ -+ bool miss_mctp_int; -+ /* Rx hardware buffer size */ -+ u32 rx_packet_count; -+ /* Rx pointer ring size */ -+ u32 rx_ring_count; -+ /* Tx pointer ring size */ -+ u32 tx_ring_count; -+ /* 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 -+ struct net_device *ndev; -+#endif -+}; ++ /* AST2700 A1 supports MMBI */ ++ if (pdev->revision != 0x27) ++ return; + -+struct mctp_client { -+ struct kref ref; -+ struct aspeed_mctp *priv; -+ struct ptr_ring tx_queue; -+ struct ptr_ring rx_queue; -+ struct list_head link; -+ wait_queue_head_t wait_queue; -+}; ++ if (pci_bmc_dev->ast2700_soc1) { ++ /* AST2700 SoC1 */ ++ start_bar = 0; ++ mmbi_max_inst = 6; ++ start_msi = 0; ++ } + -+struct mctp_type_handler { -+ u8 mctp_type; -+ u16 pci_vendor_id; -+ u16 vdm_type; -+ u16 vdm_mask; -+ struct mctp_client *client; -+ struct list_head link; -+}; ++ for (i = 0; i < mmbi_max_inst; i++) { ++ mmbi = &pci_bmc_dev->mmbi[i]; + -+union aspeed_mctp_eid_data_info { -+ struct aspeed_mctp_eid_info eid_info; -+ struct aspeed_mctp_eid_ext_info eid_ext_info; -+}; ++ /* Get MMBI BAR resource */ ++ mmbi->base = pci_resource_start(pdev, start_bar + i); ++ mmbi->mem_size = pci_resource_len(pdev, start_bar + i); + -+enum mctp_address_type { -+ ASPEED_MCTP_GENERIC_ADDR_FORMAT = 0, -+ ASPEED_MCTP_EXTENDED_ADDR_FORMAT = 1 -+}; ++ /* Check if there is bar */ ++ if (!mmbi->mem_size) ++ continue; + -+struct aspeed_mctp_endpoint { -+ union aspeed_mctp_eid_data_info data; -+ struct list_head link; -+}; ++ mmbi->mem = pci_ioremap_bar(pdev, start_bar + i); ++ if (!mmbi->mem) { ++ mmbi->mem_size = 0; ++ continue; ++ } + -+struct kmem_cache *packet_cache; ++ 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; ++ } + -+static void data_dump(struct aspeed_mctp *priv, struct mctp_pcie_packet_data *data) ++ 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); + int i; + -+ dev_dbg(priv->dev, "Address %zu", (size_t)data); -+ dev_dbg(priv->dev, "VDM header:"); -+ for (i = 0; i < PCIE_VDM_HDR_SIZE_DW; i++) { -+ dev_dbg(priv->dev, "%02x %02x %02x %02x", data->hdr[i] & 0xff, -+ (data->hdr[i] >> 8) & 0xff, (data->hdr[i] >> 16) & 0xff, -+ (data->hdr[i] >> 24) & 0xff); -+ } -+ dev_dbg(priv->dev, "Data payload:"); -+ for (i = 0; i < PCIE_VDM_DATA_SIZE_DW; i++) { -+ dev_dbg(priv->dev, "%02x %02x %02x %02x", -+ data->payload[i] & 0xff, (data->payload[i] >> 8) & 0xff, -+ (data->payload[i] >> 16) & 0xff, -+ (data->payload[i] >> 24) & 0xff); -+ } ++ for (i = 0; i < ASPEED_QUEUE_NUM; i++) ++ sysfs_remove_bin_file(&pdev->dev.kobj, &pci_bmc_dev->queue[i].bin); +} + -+void *aspeed_mctp_packet_alloc(gfp_t flags) ++static void aspeed_pci_host_bmc_device_release_vuart(struct pci_dev *pdev) +{ -+ return kmem_cache_alloc(packet_cache, flags); ++ struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); ++ int i; ++ ++ for (i = 0; i < VUART_MAX_PARMS; i++) { ++ if (pci_bmc_dev->uart_line[i] >= 0) ++ serial8250_unregister_port(pci_bmc_dev->uart_line[i]); ++ } +} -+EXPORT_SYMBOL_GPL(aspeed_mctp_packet_alloc); + -+void aspeed_mctp_packet_free(void *packet) ++static void aspeed_pci_host_bmc_device_release_memory_mapping(struct pci_dev *pdev) +{ -+ kmem_cache_free(packet_cache, packet); ++ struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); ++ ++ if (!list_empty(&pci_bmc_dev->miscdev.list)) ++ misc_deregister(&pci_bmc_dev->miscdev); +} -+EXPORT_SYMBOL_GPL(aspeed_mctp_packet_free); + -+static int _get_bdf(struct aspeed_mctp *priv) ++static void aspeed_pci_release_mmbi(struct pci_dev *pdev) +{ -+ u32 reg; -+ u16 bdf, devfn; ++ struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); ++ struct aspeed_pcie_mmbi *mmbi; ++ int i; + -+ if (priv->match_data->dma_need_64bits_width) { -+ regmap_read(priv->pcie.map, ASPEED_G7_PCIE_LOCATE, ®); -+ if (!(reg & PCIE_LOCATE_IO)) { -+ regmap_read(priv->pcie.map, ASPEED_G7_PCIE_LINK, ®); -+ if (!(reg & PCIE_G7_LINK_STS)) -+ return -ENETDOWN; -+ regmap_read(priv->map, ASPEED_G7_MCTP_PCIE_BDF, ®); -+ bdf = PCI_DEVID(PCI_BUS_NUM(reg), reg & 0xff); -+ } else { -+ regmap_read(priv->pcie.map, ASPEED_G7_IO_PCIE_LINK, -+ ®); -+ if (!(reg & PCIE_G7_IO_LINK_STS)) -+ return -ENETDOWN; -+ regmap_read(priv->map, ASPEED_G7_MCTP_PCIE_BDF, ®); -+ bdf = PCI_DEVID(PCI_BUS_NUM(reg), reg & 0xff); -+ } -+ } else { -+ regmap_read(priv->pcie.map, ASPEED_PCIE_LINK, ®); -+ if (!(reg & PCIE_LINK_STS)) -+ return -ENETDOWN; -+ regmap_read(priv->pcie.map, ASPEED_PCIE_MISC_STS_1, ®); ++ if (pdev->revision != 0x27) ++ return; + -+ reg = reg & (PCI_BUS_NUM_MASK | PCI_DEV_NUM_MASK); -+ /* only support function 0 */ -+ devfn = GET_PCI_DEV_NUM(reg) << 3; -+ bdf = PCI_DEVID(GET_PCI_BUS_NUM(reg), devfn); -+ } ++ for (i = 0; i < MMBI_MAX_INST; i++) { ++ mmbi = &pci_bmc_dev->mmbi[i]; + -+ return bdf; ++ 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 uint32_t chip_version(struct device *dev) ++static int aspeed_pci_host_setup(struct pci_dev *pdev) +{ -+ struct regmap *scu; -+ u32 revid0, revid1; ++ struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); ++ int rc = 0; + -+ 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); ++ /* Get share memory BAR */ ++ pci_bmc_dev->mem_bar_base = pci_resource_start(pdev, 0); ++ pci_bmc_dev->mem_bar_size = pci_resource_len(pdev, 0); ++ pci_bmc_dev->mem_bar_reg = pci_ioremap_bar(pdev, 0); ++ if (!pci_bmc_dev->mem_bar_reg) ++ return -ENOMEM; ++ ++ /* Get Message BAR */ ++ pci_bmc_dev->message_bar_base = pci_resource_start(pdev, 1); ++ pci_bmc_dev->message_bar_size = pci_resource_len(pdev, 1); ++ pci_bmc_dev->msg_bar_reg = pci_ioremap_bar(pdev, 1); ++ if (!pci_bmc_dev->msg_bar_reg) { ++ rc = -ENOMEM; ++ goto out_free0; + } -+ regmap_read(scu, ASPEED_REVISION_ID0, &revid0); -+ regmap_read(scu, ASPEED_REVISION_ID1, &revid1); -+ if (revid0 == ID0_AST2600A3 && revid1 == ID1_AST2600A3) { -+ /* AST2600-A3 */ -+ return ASPEED_MCTP_2600A3; -+ } else if (revid0 == ID0_AST2620A3 && revid1 == ID1_AST2620A3) { -+ /* AST2620-A3 */ -+ return ASPEED_MCTP_2600A3; -+ } else if (revid0 == ID0_AST2605A3 && revid1 == ID1_AST2605A3) { -+ /* AST2605-A3 */ -+ return ASPEED_MCTP_2600A3; -+ } else if (revid0 == ID0_AST2625A3 && revid1 == ID1_AST2625A3) { -+ /* AST2605-A3 */ -+ return ASPEED_MCTP_2600A3; ++ ++ /* AST2600 ERRTA40: dummy read */ ++ if (pdev->revision < 0x27) ++ (void)__raw_readl((void __iomem *)pci_bmc_dev->msg_bar_reg); ++ ++ rc = aspeed_pci_bmc_device_setup_queue(pdev); ++ if (rc) { ++ pr_err("Cannot setup Queue Message"); ++ goto out_free1; + } -+ return ASPEED_MCTP_2600; -+} + -+static int pcie_vdm_enable(struct device *dev) -+{ -+ int ret = 0; -+ struct regmap *scu; -+ const struct aspeed_mctp_match_data *match_data = -+ of_device_get_match_data(dev); ++ rc = aspeed_pci_bmc_device_setup_memory_mapping(pdev); ++ if (rc) { ++ pr_err("Cannot setup Memory Mapping"); ++ goto out_free_queue; ++ } + -+ 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); ++ rc = aspeed_pci_bmc_device_setup_mbox(pdev); ++ if (rc) { ++ pr_err("Cannot setup Mailnbox"); ++ goto out_free_mmapping; + } -+ ret = regmap_update_bits(scu, match_data->scu_pcie_ctrl_offset, -+ ASPEED_G7_SCU_PCIE_CTRL_VDM_EN, -+ ASPEED_G7_SCU_PCIE_CTRL_VDM_EN); -+ return ret; ++ ++ rc = aspeed_pci_bmc_device_setup_vuart(pdev); ++ if (rc) { ++ pr_err("Cannot setup Virtual UART"); ++ goto out_free_mbox; ++ } ++ ++ rc = devm_request_irq(&pdev->dev, pci_irq_vector(pdev, pci_bmc_dev->msi_idx_table[BMC_MSI]), ++ aspeed_pci_host_bmc_device_interrupt, IRQF_SHARED, ++ pci_bmc_dev->miscdev.name, pci_bmc_dev); ++ if (rc) { ++ pr_err("Get BMC DEVICE IRQ failed. (err=%d)\n", rc); ++ goto out_free_uart; ++ } ++ ++ /* Setup AST2700 PCIe MMBI device */ ++ aspeed_pci_bmc_device_setup_mmbi(pdev); ++ ++ return 0; ++ ++out_free_uart: ++ aspeed_pci_host_bmc_device_release_vuart(pdev); ++out_free_mbox: ++ devm_free_irq(&pdev->dev, pci_irq_vector(pdev, pci_bmc_dev->msi_idx_table[MBX_MSI]), ++ pci_bmc_dev); ++out_free_mmapping: ++ aspeed_pci_host_bmc_device_release_memory_mapping(pdev); ++out_free_queue: ++ aspeed_pci_host_bmc_device_release_queue(pdev); ++out_free1: ++ pci_iounmap(pdev, pci_bmc_dev->msg_bar_reg); ++out_free0: ++ pci_iounmap(pdev, pci_bmc_dev->mem_bar_reg); ++ ++ pci_release_regions(pdev); ++ return rc; +} + -+/* -+ * HW produces and expects VDM header in little endian and payload in network order. -+ * To allow userspace to use network order for the whole packet, PCIe VDM header needs -+ * to be swapped. -+ */ -+static void aspeed_mctp_swap_pcie_vdm_hdr(struct mctp_pcie_packet_data *data) ++static int aspeed_pci_host_mmbi_device_setup(struct pci_dev *pdev) +{ -+ int i; -+ -+ for (i = 0; i < PCIE_VDM_HDR_SIZE_DW; i++) -+ data->hdr[i] = swab32(data->hdr[i]); ++ aspeed_pci_bmc_device_setup_mmbi(pdev); ++ return 0; +} + -+static void aspeed_mctp_rx_trigger(struct mctp_channel *rx) ++static struct aspeed_platform aspeed_pcie_host[] = { ++ { .setup = aspeed_pci_host_setup }, ++ { .setup = aspeed_pci_host_mmbi_device_setup }, ++ { 0 } ++}; ++ ++static int aspeed_pci_host_bmc_device_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ -+ struct aspeed_mctp *priv = container_of(rx, typeof(*priv), rx); -+ u32 reg; ++ struct aspeed_pci_bmc_dev *pci_bmc_dev; ++ int rc = 0; + -+ /* -+ * Even though rx_buf_addr doesn't change, if we don't do the write -+ * here, the HW doesn't trigger RX. We're also clearing the -+ * RX_CMD_READY bit, otherwise we're observing a rare case where -+ * trigger isn't registered by the HW, and we're ending up with stuck -+ * HW (not reacting to wr_ptr writes). -+ * Also, note that we're writing 0 as wr_ptr. If we're writing other -+ * value, the HW behaves in a bizarre way that's hard to explain... -+ */ -+ regmap_update_bits(priv->map, ASPEED_MCTP_CTRL, RX_CMD_READY, 0); -+ if (priv->match_data->fifo_auto_surround) { -+ regmap_write(priv->map, ASPEED_MCTP_RX_BUF_ADDR, -+ rx->cmd.dma_handle); -+ if (priv->match_data->dma_need_64bits_width) -+ regmap_write(priv->map, ASPEED_MCTP_RX_BUF_HI_ADDR, -+ upper_32_bits(rx->cmd.dma_handle)); -+ } else { -+ regmap_read(priv->map, ASPEED_MCTP_RX_BUF_ADDR, ®); -+ if (!reg) { -+ regmap_write(priv->map, ASPEED_MCTP_RX_BUF_ADDR, -+ rx->cmd.dma_handle); -+ } else if (reg == (rx->cmd.dma_handle & GENMASK(28, 3))) { -+ dev_info(priv->dev, -+ "Already initialized - skipping rx dma set\n"); -+ } else { -+ dev_err(priv->dev, -+ "The memory of rx dma can't be changed after the controller is activated\n"); -+ return; -+ } ++ pr_info("ASPEED BMC PCI ID %04x:%04x, IRQ=%u\n", pdev->vendor, pdev->device, pdev->irq); ++ ++ pci_bmc_dev = devm_kzalloc(&pdev->dev, sizeof(*pci_bmc_dev), GFP_KERNEL); ++ if (!pci_bmc_dev) ++ return -ENOMEM; ++ ++ /* Get platform id */ ++ pci_bmc_dev->driver_data = ent->driver_data; ++ pci_bmc_dev->platform = &aspeed_pcie_host[ent->driver_data]; ++ ++ pci_bmc_dev->id = ida_simple_get(&bmc_device_ida, 0, 0, GFP_KERNEL); ++ if (pci_bmc_dev->id < 0) ++ return pci_bmc_dev->id; ++ ++ rc = pci_enable_device(pdev); ++ if (rc) { ++ dev_err(&pdev->dev, "pci_enable_device() returned error %d\n", rc); ++ return rc; + } -+ regmap_write(priv->map, ASPEED_MCTP_RX_BUF_WR_PTR, 0); + -+ /* After re-enabling RX we need to restart WA logic */ -+ if (priv->rx_runaway_wa.enable) -+ priv->rx.buffer_count = priv->rx_packet_count; -+ /* -+ * When Rx warmup MCTP controller may store first packet into the 0th to the -+ * 3rd cmd. In ast2600 A3, If the packet isn't stored in the 0th cmd we need -+ * to change the rx buffer size to avoid rx runaway in first loop. In ast2600 -+ * A1/A2, after first loop hardware is guaranteed to use (RX_PACKET_COUNT - 4) -+ * buffers. -+ */ -+ priv->rx_warmup = true; -+ priv->rx_runaway_wa.first_loop = true; -+ priv->rx_runaway_wa.packet_counter = 0; ++ pci_set_master(pdev); ++ pci_set_drvdata(pdev, pci_bmc_dev); ++ ++ /* Prepare IRQ resource */ ++ aspeed_pci_setup_irq_resource(pdev); ++ ++ /* Setup BMC PCI device */ ++ rc = pci_bmc_dev->platform->setup(pdev); ++ if (rc) { ++ dev_err(&pdev->dev, "ASPEED PCIe Host device returned error %d\n", rc); ++ pci_free_irq_vectors(pdev); ++ pci_disable_device(pdev); ++ return rc; ++ } + -+ regmap_update_bits(priv->map, ASPEED_MCTP_CTRL, RX_CMD_READY, -+ RX_CMD_READY); ++ return 0; +} + -+static void aspeed_mctp_tx_trigger(struct mctp_channel *tx, bool notify) ++static void aspeed_pci_host_bmc_device_remove(struct pci_dev *pdev) +{ -+ struct aspeed_mctp *priv = container_of(tx, typeof(*priv), tx); -+ u32 ctrl_val; -+ int ret; -+ -+ if (notify) { -+ if (priv->match_data->dma_need_64bits_width) { -+ struct aspeed_g7_mctp_tx_cmd *last_cmd; ++ struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); + -+ last_cmd = (struct aspeed_g7_mctp_tx_cmd *)tx->cmd.vaddr + -+ (tx->wr_ptr - 1) % TX_PACKET_COUNT; -+ last_cmd->tx_lo |= TX_INTERRUPT_AFTER_CMD; -+ } else { -+ struct aspeed_mctp_tx_cmd *last_cmd; ++ 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); + -+ last_cmd = (struct aspeed_mctp_tx_cmd *)tx->cmd.vaddr + -+ (tx->wr_ptr - 1) % TX_PACKET_COUNT; -+ last_cmd->tx_lo |= TX_INTERRUPT_AFTER_CMD; -+ } ++ 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); + } -+ if (priv->match_data->fifo_auto_surround) -+ regmap_write(priv->map, ASPEED_MCTP_TX_BUF_WR_PTR, tx->wr_ptr); -+ regmap_update_bits(priv->map, ASPEED_MCTP_CTRL, TX_CMD_TRIGGER, -+ TX_CMD_TRIGGER); -+ ret = regmap_read_poll_timeout_atomic(priv->map, ASPEED_MCTP_CTRL, -+ ctrl_val, -+ !(ctrl_val & TX_CMD_TRIGGER), 0, -+ 1000000); -+ if (ret) { -+ u32 rd_ptr, wr_ptr; + -+ regmap_write(priv->map, ASPEED_MCTP_TX_BUF_RD_PTR, UPDATE_RX_RD_PTR); -+ regmap_read(priv->map, ASPEED_MCTP_TX_BUF_RD_PTR, &rd_ptr); -+ rd_ptr &= RX_BUF_RD_PTR_MASK; -+ regmap_read(priv->map, ASPEED_MCTP_TX_BUF_WR_PTR, &wr_ptr); -+ wr_ptr &= TX_BUF_RD_PTR_MASK; -+ dev_warn(priv->dev, -+ "Wait tx completed timeout rd_ptr = %x, wr_ptr = %x\n", -+ rd_ptr, wr_ptr); -+ regmap_update_bits(priv->map, ASPEED_MCTP_CTRL, TX_CMD_TRIGGER, -+ 0); -+ } -+} ++ aspeed_pci_release_mmbi(pdev); + -+static void aspeed_mctp_tx_cmd_prep(u32 *tx_hdr, struct aspeed_mctp_tx_cmd *tx_cmd) -+{ -+ u32 packet_size, target_id; -+ u8 dest_eid, padding_len, routing_type, tag_owner; ++ ida_simple_remove(&bmc_device_ida, pci_bmc_dev->id); + -+ packet_size = FIELD_GET(MCTP_HDR_DW_LE_PACKET_SIZE, tx_hdr[0]); -+ routing_type = FIELD_GET(MCTP_HDR_DW_LE_ROUTING_TYPE, tx_hdr[0]); -+ routing_type = routing_type ? routing_type - 1 : 0; -+ padding_len = FIELD_GET(MCTP_HDR_DW_LE_PADDING_LEN, tx_hdr[1]); -+ target_id = FIELD_GET(MCTP_HDR_DW_LE_TARGET_ID, tx_hdr[2]); -+ tag_owner = FIELD_GET(MCTP_HDR_DW_LE_TAG_OWNER, tx_hdr[3]); -+ dest_eid = FIELD_GET(MCTP_HDR_DW_LE_DEST_EID, tx_hdr[3]); ++ pci_iounmap(pdev, pci_bmc_dev->msg_bar_reg); ++ pci_iounmap(pdev, pci_bmc_dev->mem_bar_reg); + -+ tx_cmd->tx_hi = FIELD_PREP(TX_PACKET_DEST_EID, dest_eid); -+ tx_cmd->tx_lo = FIELD_PREP(TX_PACKET_TARGET_ID, target_id) | -+ TX_INTERRUPT_AFTER_CMD | -+ FIELD_PREP(TX_PACKET_ROUTING_TYPE, routing_type) | -+ FIELD_PREP(TX_PACKET_TAG_OWNER, tag_owner) | -+ TX_PACKET_SIZE_2500(packet_size) | -+ FIELD_PREP(TX_PACKET_PADDING_LEN, padding_len); ++ pci_free_irq_vectors(pdev); ++ pci_release_regions(pdev); ++ pci_disable_device(pdev); +} + -+static void aspeed_mctp_emit_tx_cmd(struct mctp_channel *tx, -+ struct mctp_pcie_packet *packet) -+{ -+ struct aspeed_mctp *priv = container_of(tx, typeof(*priv), tx); -+ struct aspeed_mctp_tx_cmd *tx_cmd = -+ (struct aspeed_mctp_tx_cmd *)tx->cmd.vaddr + tx->wr_ptr; -+ struct aspeed_g7_mctp_tx_cmd *tx_cmd_g7 = -+ (struct aspeed_g7_mctp_tx_cmd *)tx->cmd.vaddr + tx->wr_ptr; -+ u32 packet_sz_dw = packet->size / sizeof(u32) - -+ sizeof(packet->data.hdr) / sizeof(u32); -+ u32 offset; ++/** ++ * This table holds the list of (VendorID,DeviceID) supported by this driver ++ * ++ */ ++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 }, ++ { ++ 0, ++ } ++}; + -+ data_dump(priv, &packet->data); -+ aspeed_mctp_swap_pcie_vdm_hdr(&packet->data); ++MODULE_DEVICE_TABLE(pci, aspeed_host_bmc_dev_pci_ids); + -+ if (priv->match_data->vdm_hdr_direct_xfer) { -+ offset = tx->wr_ptr * sizeof(packet->data); -+ memcpy((u8 *)tx->data.vaddr + offset, &packet->data, -+ sizeof(packet->data)); -+ if (priv->match_data->dma_need_64bits_width) { -+ tx_cmd_g7->tx_lo = TX_PACKET_SIZE(packet_sz_dw); -+ tx_cmd_g7->tx_mid = TX_RESERVED_1; -+ tx_cmd_g7->tx_mid |= ((tx->data.dma_handle + offset) & -+ GENMASK(31, 4)); -+ tx_cmd_g7->tx_hi = upper_32_bits((tx->data.dma_handle + offset)); -+ } else { -+ tx_cmd->tx_lo = TX_PACKET_SIZE(packet_sz_dw); -+ tx_cmd->tx_hi = TX_RESERVED_1; -+ tx_cmd->tx_hi |= TX_DATA_ADDR(tx->data.dma_handle + offset); -+ } -+ } else { -+ offset = tx->wr_ptr * sizeof(struct mctp_pcie_packet_data_2500); -+ memcpy((u8 *)tx->data.vaddr + offset, packet->data.payload, -+ sizeof(packet->data.payload)); -+ aspeed_mctp_tx_cmd_prep(packet->data.hdr, tx_cmd); -+ tx_cmd->tx_hi |= TX_DATA_ADDR_2500(tx->data.dma_handle + offset); -+ if (tx->wr_ptr == TX_PACKET_COUNT - 1) -+ tx_cmd->tx_hi |= TX_LAST_CMD; -+ } -+ dev_dbg(priv->dev, "tx->wr_prt: %d, tx_cmd: hi:%08x lo:%08x\n", -+ tx->wr_ptr, tx_cmd->tx_hi, tx_cmd->tx_lo); ++static struct pci_driver aspeed_host_bmc_dev_driver = { ++ .name = DRIVER_NAME, ++ .id_table = aspeed_host_bmc_dev_pci_ids, ++ .probe = aspeed_pci_host_bmc_device_probe, ++ .remove = aspeed_pci_host_bmc_device_remove, ++}; + -+ tx->wr_ptr = (tx->wr_ptr + 1) % TX_PACKET_COUNT; ++static int __init aspeed_host_bmc_device_init(void) ++{ ++ return pci_register_driver(&aspeed_host_bmc_dev_driver); +} + -+static struct mctp_client *aspeed_mctp_client_alloc(struct aspeed_mctp *priv) ++static void aspeed_host_bmc_device_exit(void) +{ -+ struct mctp_client *client; ++ /* unregister pci driver */ ++ pci_unregister_driver(&aspeed_host_bmc_dev_driver); ++} + -+ client = kzalloc(sizeof(*client), GFP_KERNEL); -+ if (!client) -+ goto out; ++late_initcall(aspeed_host_bmc_device_init); ++module_exit(aspeed_host_bmc_device_exit); + -+ kref_init(&client->ref); -+ client->priv = priv; -+ ptr_ring_init(&client->tx_queue, priv->tx_ring_count, GFP_KERNEL); -+ ptr_ring_init(&client->rx_queue, priv->rx_ring_count, GFP_ATOMIC); ++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 +@@ -0,0 +1,406 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright 2017 IBM Corporation ++ * Copyright 2021 Aspeed Technology Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+out: -+ return client; -+} ++#define DEVICE_NAME "aspeed-mbox" + -+static void aspeed_mctp_client_free(struct kref *ref) ++#define ASPEED_MBOX_DR(dr, n) (dr + (n * 4)) ++#define ASPEED_MBOX_STR(str, n) (str + (n / 8) * 4) ++#define ASPEED_MBOX_BIE(bie, n) (bie + (n / 8) * 4) ++#define ASPEED_MBOX_HIE(hie, n) (hie + (n / 8) * 4) ++ ++#define ASPEED_MBOX_BCR_RECV BIT(7) ++#define ASPEED_MBOX_BCR_MASK BIT(1) ++#define ASPEED_MBOX_BCR_SEND BIT(0) ++ ++/* ioctl code */ ++#define ASPEED_MBOX_IOCTL 0xA3 ++#define ASPEED_MBOX_IOCTL_GET_SIZE \ ++ _IOR(ASPEED_MBOX_IOCTL, 0, struct aspeed_mbox_ioctl_data) ++ ++struct aspeed_mbox_ioctl_data { ++ unsigned int data; ++}; ++ ++struct aspeed_mbox_model { ++ unsigned int dr_num; ++ ++ /* offsets to the MBOX registers */ ++ unsigned int dr; ++ unsigned int str; ++ unsigned int bcr; ++ unsigned int hcr; ++ unsigned int bie; ++ unsigned int hie; ++}; ++ ++struct aspeed_mbox { ++ struct miscdevice miscdev; ++ struct regmap *map; ++ unsigned int base; ++ wait_queue_head_t queue; ++ struct mutex mutex; ++ const struct aspeed_mbox_model *model; ++}; ++ ++static atomic_t aspeed_mbox_open_count = ATOMIC_INIT(0); ++ ++static u8 aspeed_mbox_inb(struct aspeed_mbox *mbox, int reg) +{ -+ struct mctp_client *client = container_of(ref, typeof(*client), ref); ++ /* ++ * The mbox registers are actually only one byte but are addressed ++ * four bytes apart. The other three bytes are marked 'reserved', ++ * they *should* be zero but lets not rely on it. ++ * I am going to rely on the fact we can casually read/write to them... ++ */ ++ unsigned int val = 0xff; /* If regmap throws an error return 0xff */ ++ int rc = regmap_read(mbox->map, mbox->base + reg, &val); + -+ ptr_ring_cleanup(&client->rx_queue, &aspeed_mctp_packet_free); -+ ptr_ring_cleanup(&client->tx_queue, &aspeed_mctp_packet_free); ++ if (rc) ++ dev_err(mbox->miscdev.parent, "regmap_read() failed with " ++ "%d (reg: 0x%08x)\n", rc, reg); + -+ kfree(client); ++ return val & 0xff; +} + -+static void aspeed_mctp_client_get(struct mctp_client *client) ++static void aspeed_mbox_outb(struct aspeed_mbox *mbox, u8 data, int reg) +{ -+ lockdep_assert_held(&client->priv->clients_lock); ++ int rc = regmap_write(mbox->map, mbox->base + reg, data); + -+ kref_get(&client->ref); ++ if (rc) ++ dev_err(mbox->miscdev.parent, "regmap_write() failed with " ++ "%d (data: %u reg: 0x%08x)\n", rc, data, reg); +} + -+static void aspeed_mctp_client_put(struct mctp_client *client) ++static struct aspeed_mbox *file_mbox(struct file *file) +{ -+ kref_put(&client->ref, &aspeed_mctp_client_free); ++ return container_of(file->private_data, struct aspeed_mbox, miscdev); +} + -+static struct mctp_client * -+aspeed_mctp_find_handler(struct aspeed_mctp *priv, -+ struct mctp_pcie_packet *packet) ++static int aspeed_mbox_open(struct inode *inode, struct file *file) +{ -+ struct mctp_type_handler *handler; -+ u8 *payload = (u8 *)packet->data.payload; -+ struct mctp_client *client = NULL; -+ u8 mctp_type; -+ u16 vendor = 0; -+ u16 vdm_type = 0; -+ -+ lockdep_assert_held(&priv->clients_lock); ++ struct aspeed_mbox *mbox = file_mbox(file); ++ const struct aspeed_mbox_model *model = mbox->model; + -+ mctp_type = payload[MCTP_PAYLOAD_TYPE_OFFSET]; -+ if (mctp_type == MCTP_HDR_TYPE_VDM_PCI) { -+ vendor = *((u16 *)&payload[MCTP_PAYLOAD_VENDOR_OFFSET]); -+ vdm_type = *((u16 *)&payload[MCTP_PAYLOAD_VDM_TYPE_OFFSET]); ++ if (atomic_inc_return(&aspeed_mbox_open_count) == 1) { ++ /* ++ * Clear the interrupt status bit if it was left on and unmask ++ * interrupts. ++ * ASPEED_MBOX_BCR_RECV bit is W1C, this also unmasks in 1 step ++ */ ++ aspeed_mbox_outb(mbox, ASPEED_MBOX_BCR_RECV, model->bcr); ++ return 0; + } + -+ list_for_each_entry(handler, &priv->mctp_type_handlers, link) { -+ if (handler->mctp_type == mctp_type && -+ handler->pci_vendor_id == vendor && -+ handler->vdm_type == (vdm_type & handler->vdm_mask)) { -+ dev_dbg(priv->dev, "Found client for type %x vdm %x\n", -+ mctp_type, handler->vdm_type); -+ client = handler->client; -+ break; -+ } -+ } -+ return client; ++ atomic_dec(&aspeed_mbox_open_count); ++ return -EBUSY; +} + -+static void aspeed_mctp_dispatch_packet(struct aspeed_mctp *priv, -+ struct mctp_pcie_packet *packet) ++static ssize_t aspeed_mbox_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) +{ -+ struct mctp_client *client; -+ int ret; ++ struct aspeed_mbox *mbox = file_mbox(file); ++ const struct aspeed_mbox_model *model = mbox->model; ++ char __user *p = buf; ++ ssize_t ret; ++ int i; + -+ spin_lock(&priv->clients_lock); ++ if (!access_ok(buf, count)) ++ return -EFAULT; + -+ client = aspeed_mctp_find_handler(priv, packet); ++ if (count + *ppos > model->dr_num) ++ return -EINVAL; + -+ if (!client) -+ client = priv->default_client; ++ if (file->f_flags & O_NONBLOCK) { ++ if (!(aspeed_mbox_inb(mbox, model->bcr) & ++ ASPEED_MBOX_BCR_RECV)) ++ return -EAGAIN; ++ } else if (wait_event_interruptible(mbox->queue, ++ aspeed_mbox_inb(mbox, model->bcr) & ++ ASPEED_MBOX_BCR_RECV)) { ++ return -ERESTARTSYS; ++ } + -+ if (client) -+ aspeed_mctp_client_get(client); ++ mutex_lock(&mbox->mutex); + -+ spin_unlock(&priv->clients_lock); ++ for (i = *ppos; count > 0 && i < model->dr_num; i++) { ++ uint8_t reg = aspeed_mbox_inb(mbox, ASPEED_MBOX_DR(model->dr, i)); + -+ if (client) { -+ ret = ptr_ring_produce(&client->rx_queue, packet); -+ if (ret) { -+ /* -+ * This can happen if client process does not -+ * consume packets fast enough -+ */ -+ dev_dbg(priv->dev, "Failed to store packet in client RX queue\n"); -+ aspeed_mctp_packet_free(packet); -+ } else { -+ wake_up_all(&client->wait_queue); -+ } -+#ifdef CONFIG_MCTP_TRANSPORT_PCIE_VDM -+ mctp_pcie_vdm_receive_packet(priv->ndev); -+#endif -+ aspeed_mctp_client_put(client); -+ } else { -+ dev_dbg(priv->dev, "Failed to dispatch RX packet\n"); -+ aspeed_mctp_packet_free(packet); ++ ret = __put_user(reg, p); ++ if (ret) ++ goto out_unlock; ++ ++ p++; ++ count--; + } ++ ++ /* ASPEED_MBOX_BCR_RECV bit is write to clear, this also unmasks in 1 step */ ++ aspeed_mbox_outb(mbox, ASPEED_MBOX_BCR_RECV, model->bcr); ++ ret = p - buf; ++ ++out_unlock: ++ mutex_unlock(&mbox->mutex); ++ return ret; +} + -+static void aspeed_mctp_tx_tasklet(unsigned long data) ++static ssize_t aspeed_mbox_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) +{ -+ struct mctp_channel *tx = (struct mctp_channel *)data; -+ struct aspeed_mctp *priv = container_of(tx, typeof(*priv), tx); -+ struct mctp_client *client; -+ bool trigger = false; -+ bool full = false; -+ u32 rd_ptr; ++ struct aspeed_mbox *mbox = file_mbox(file); ++ const struct aspeed_mbox_model *model = mbox->model; ++ const char __user *p = buf; ++ ssize_t ret; ++ char c; ++ int i; + -+ if (priv->match_data->fifo_auto_surround) { -+ regmap_write(priv->map, ASPEED_MCTP_TX_BUF_RD_PTR, UPDATE_RX_RD_PTR); -+ regmap_read(priv->map, ASPEED_MCTP_TX_BUF_RD_PTR, &rd_ptr); -+ rd_ptr &= TX_BUF_RD_PTR_MASK; -+ } else { -+ rd_ptr = tx->rd_ptr; -+ } ++ if (!access_ok(buf, count)) ++ return -EFAULT; + -+ spin_lock(&priv->clients_lock); ++ if (count + *ppos > model->dr_num) ++ return -EINVAL; + -+ list_for_each_entry(client, &priv->clients, link) { -+ while (!(full = (tx->wr_ptr + 1) % TX_PACKET_COUNT == rd_ptr)) { -+ struct mctp_pcie_packet *packet; ++ mutex_lock(&mbox->mutex); + -+ packet = ptr_ring_consume(&client->tx_queue); -+ if (!packet) -+ break; ++ for (i = *ppos; count > 0 && i < model->dr_num; i++) { ++ ret = __get_user(c, p); ++ if (ret) ++ goto out_unlock; + -+ aspeed_mctp_emit_tx_cmd(tx, packet); -+ aspeed_mctp_packet_free(packet); -+ trigger = true; -+ } ++ aspeed_mbox_outb(mbox, c, ASPEED_MBOX_DR(model->dr, i)); ++ p++; ++ count--; + } + -+ spin_unlock(&priv->clients_lock); ++ aspeed_mbox_outb(mbox, ASPEED_MBOX_BCR_SEND, model->bcr); ++ ret = p - buf; + -+ if (trigger) -+ aspeed_mctp_tx_trigger(tx, full); ++out_unlock: ++ mutex_unlock(&mbox->mutex); ++ return ret; +} + -+static void aspeed_mctp_rx_hdr_prep(struct aspeed_mctp *priv, u8 *hdr, u32 rx_lo) ++static __poll_t aspeed_mbox_poll(struct file *file, poll_table *wait) +{ -+ u16 bdf; -+ u8 routing_type; ++ struct aspeed_mbox *mbox = file_mbox(file); ++ const struct aspeed_mbox_model *model = mbox->model; ++ __poll_t mask = 0; + -+ /* -+ * MCTP controller will map the routing type to reduce one bit -+ * 0 (Route to RC) -> 0, -+ * 2 (Route by ID) -> 1, -+ * 3 (Broadcast from RC) -> 2 -+ */ -+ routing_type = FIELD_GET(RX_PACKET_ROUTING_TYPE, rx_lo); -+ routing_type = routing_type ? routing_type + 1 : 0; -+ bdf = _get_bdf(priv); -+ /* Length[7:0] */ -+ hdr[0] = FIELD_GET(RX_PACKET_SIZE, rx_lo); -+ /* TD:EP:ATTR[1:0]:R or AT[1:0]:Length[9:8] */ -+ hdr[1] = 0; -+ /* R or T9:TC[2:0]:R[3:0] */ -+ hdr[2] = 0; -+ /* R or Fmt[2]:Fmt[1:0]=b'11:Type[4:3]=b'10:Type[2:0] */ -+ hdr[3] = 0x70 | routing_type; -+ /* VDM message code = 0x7f */ -+ hdr[4] = 0x7f; -+ /* R[1:0]:Pad len[1:0]:MCTP VDM Code[3:0] */ -+ hdr[5] = FIELD_GET(RX_PACKET_PADDING_LEN, rx_lo) << 4; -+ /* TODO: PCI Requester ID: HW didn't get this information */ -+ hdr[6] = 0; -+ hdr[7] = 5; -+ /* Vendor ID: 0x1AB4 */ -+ hdr[8] = 0xb4; -+ hdr[9] = 0x1a; -+ /* PCI Target ID */ -+ hdr[10] = bdf & 0xff; -+ hdr[11] = bdf >> 8 & 0xff; -+ /* SOM:EOM:Pkt Seq#[1:0]:TO:Msg Tag[2:0]*/ -+ hdr[12] = FIELD_GET(RX_PACKET_SOM, rx_lo) << 7 | -+ FIELD_GET(RX_PACKET_EOM, rx_lo) << 6 | -+ FIELD_GET(RX_PACKET_SEQ_NUMBER, rx_lo) << 4 | -+ FIELD_GET(RX_PACKET_TAG_OWNER, rx_lo) << 3 | -+ FIELD_GET(RX_PACKET_MSG_TAG, rx_lo); -+ /* Source Endpoint ID */ -+ hdr[13] = FIELD_GET(RX_PACKET_SRC_EID, rx_lo); -+ /* Destination Endpoint ID: HW didn't get this information*/ -+ hdr[14] = priv->eid; -+ /* TODO: R[3:0]: header version[3:0] */ -+ hdr[15] = 1; ++ poll_wait(file, &mbox->queue, wait); ++ ++ if (aspeed_mbox_inb(mbox, model->bcr) & ASPEED_MBOX_BCR_RECV) ++ mask |= POLLIN; ++ ++ return mask; +} + -+static void aspeed_mctp_rx_tasklet(unsigned long data) ++static int aspeed_mbox_release(struct inode *inode, struct file *file) +{ -+ struct mctp_channel *rx = (struct mctp_channel *)data; -+ struct aspeed_mctp *priv = container_of(rx, typeof(*priv), rx); -+ struct mctp_pcie_packet *rx_packet; -+ struct aspeed_mctp_rx_cmd *rx_cmd; -+ u32 hw_read_ptr; -+ u32 *hdr, *payload; -+ bool rx_full; ++ atomic_dec(&aspeed_mbox_open_count); ++ return 0; ++} + -+ /* initialized as false */ -+ rx_full = false; ++static long aspeed_mbox_ioctl(struct file *file, unsigned int cmd, ++ unsigned long param) ++{ ++ long ret = 0; ++ struct aspeed_mbox *mbox = file_mbox(file); ++ const struct aspeed_mbox_model *model = mbox->model; ++ struct aspeed_mbox_ioctl_data data; ++ ++ switch (cmd) { ++ case ASPEED_MBOX_IOCTL_GET_SIZE: ++ data.data = model->dr_num; ++ if (copy_to_user((void __user *)param, &data, sizeof(data))) ++ ret = -EFAULT; ++ break; ++ default: ++ ret = -ENOTTY; ++ break; ++ } + -+ if (priv->match_data->vdm_hdr_direct_xfer && priv->match_data->fifo_auto_surround) { -+ struct mctp_pcie_packet_data *rx_buf; -+ u32 residual_cmds = 0; ++ return ret; ++} + -+ /* Trigger HW read pointer update, must be done before RX loop */ -+ regmap_write(priv->map, ASPEED_MCTP_RX_BUF_RD_PTR, UPDATE_RX_RD_PTR); ++static const struct file_operations aspeed_mbox_fops = { ++ .owner = THIS_MODULE, ++ .llseek = no_seek_end_llseek, ++ .read = aspeed_mbox_read, ++ .write = aspeed_mbox_write, ++ .open = aspeed_mbox_open, ++ .release = aspeed_mbox_release, ++ .poll = aspeed_mbox_poll, ++ .unlocked_ioctl = aspeed_mbox_ioctl, ++}; + -+ /* -+ * rx->stopped indicates if rx ring is full or not. -+ * Use rx_full to note ring status before consuming packet. -+ */ -+ rx_full = rx->stopped; ++static irqreturn_t aspeed_mbox_irq(int irq, void *arg) ++{ ++ struct aspeed_mbox *mbox = arg; ++ const struct aspeed_mbox_model *model = mbox->model; + -+ /* -+ * XXX: Using rd_ptr obtained from HW is unreliable so we need to -+ * maintain the state of buffer on our own by peeking into the buffer -+ * and checking where the packet was written. -+ */ -+ rx_buf = (struct mctp_pcie_packet_data *)rx->data.vaddr; -+ hdr = (u32 *)&rx_buf[rx->wr_ptr]; -+ if (!*hdr && priv->rx_warmup) { -+ u32 tmp_wr_ptr = rx->wr_ptr; ++ if (!(aspeed_mbox_inb(mbox, model->bcr) & ASPEED_MBOX_BCR_RECV)) ++ return IRQ_NONE; + -+ /* -+ * HACK: Right after start the RX hardware can put received -+ * packet into an unexpected offset - in order to locate -+ * received packet driver has to scan all RX data buffers. -+ */ -+ do { -+ tmp_wr_ptr = (tmp_wr_ptr + 1) % priv->rx_packet_count; ++ /* ++ * Leave the status bit set so that we know the data is for us, ++ * clear it once it has been read. ++ */ + -+ hdr = (u32 *)&rx_buf[tmp_wr_ptr]; -+ } while (!*hdr && tmp_wr_ptr != rx->wr_ptr); ++ /* Mask it off, we'll clear it when we the data gets read */ ++ aspeed_mbox_outb(mbox, ASPEED_MBOX_BCR_MASK, model->bcr); + -+ if (tmp_wr_ptr != rx->wr_ptr) { -+ dev_warn(priv->dev, -+ "Runaway RX packet found %d -> %d\n", -+ rx->wr_ptr, tmp_wr_ptr); -+ residual_cmds = abs(tmp_wr_ptr - rx->wr_ptr); -+ rx->wr_ptr = tmp_wr_ptr; -+ if (!priv->rx_runaway_wa.enable && -+ priv->rx_warmup) -+ regmap_write(priv->map, ASPEED_MCTP_RX_BUF_SIZE, -+ rx->buffer_count - residual_cmds); -+ priv->rx_warmup = false; -+ } -+ } else { -+ priv->rx_warmup = false; -+ } ++ wake_up(&mbox->queue); ++ return IRQ_HANDLED; ++} + -+ if (priv->rx_runaway_wa.packet_counter > priv->rx_packet_count && -+ priv->rx_runaway_wa.first_loop) { -+ if (priv->rx_runaway_wa.enable) -+ /* -+ * Once we receive RX_PACKET_COUNT packets, hardware is -+ * guaranteed to use (RX_PACKET_COUNT - 4) buffers. Decrease -+ * buffer count by 4, then we can turn off scanning of RX -+ * buffers. RX buffer scanning should be enabled every time -+ * RX hardware is started. -+ * This is just a performance optimization - we could keep -+ * scanning RX buffers forever, but under heavy traffic it is -+ * fairly common that rx_tasklet is executed while RX buffer -+ * ring is empty. -+ */ -+ rx->buffer_count = priv->rx_packet_count - 4; -+ else -+ /* -+ * Once we receive RX_PACKET_COUNT packets, we need to restore the -+ * RX buffer size to 4 byte aligned value to avoid rx runaway. -+ */ -+ regmap_write(priv->map, ASPEED_MCTP_RX_BUF_SIZE, -+ rx->buffer_count); -+ priv->rx_runaway_wa.first_loop = false; -+ } ++static int aspeed_mbox_config_irq(struct aspeed_mbox *mbox, ++ struct platform_device *pdev) ++{ ++ const struct aspeed_mbox_model *model = mbox->model; ++ struct device *dev = &pdev->dev; ++ int i, rc, irq; + -+ while (*hdr != 0) { -+ if (FIELD_GET(MCTP_HDR_DW_LE_PACKET_SIZE, hdr[0]) * 4 > -+ ASPEED_MCTP_MTU) -+ dev_warn(priv->dev, -+ "Rx length %ld > MTU size %d\n", -+ FIELD_GET(MCTP_HDR_DW_LE_PACKET_SIZE, -+ hdr[0]) * -+ 4, -+ ASPEED_MCTP_MTU); -+ rx_packet = aspeed_mctp_packet_alloc(GFP_ATOMIC); -+ if (rx_packet) { -+ memcpy(&rx_packet->data, hdr, sizeof(rx_packet->data)); -+ aspeed_mctp_swap_pcie_vdm_hdr(&rx_packet->data); ++ irq = irq_of_parse_and_map(dev->of_node, 0); ++ if (!irq) ++ return -ENODEV; + -+ aspeed_mctp_dispatch_packet(priv, rx_packet); -+ } else { -+ dev_dbg(priv->dev, "Failed to allocate RX packet\n"); -+ } -+ data_dump(priv, &rx_packet->data); -+ *hdr = 0; -+ rx->wr_ptr = (rx->wr_ptr + 1) % rx->buffer_count; -+ hdr = (u32 *)&rx_buf[rx->wr_ptr]; ++ rc = devm_request_irq(dev, irq, aspeed_mbox_irq, ++ IRQF_SHARED, DEVICE_NAME, mbox); ++ if (rc < 0) { ++ dev_err(dev, "Unable to request IRQ %d\n", irq); ++ return rc; ++ } + -+ priv->rx_runaway_wa.packet_counter++; -+ } ++ /* ++ * Disable all register based interrupts. ++ */ ++ for (i = 0; i < model->dr_num / 8; ++i) ++ aspeed_mbox_outb(mbox, 0x00, ASPEED_MBOX_BIE(model->bie, i)); + -+ /* -+ * Update HW write pointer, this can be done only after driver consumes -+ * packets from RX ring. -+ */ -+ regmap_read(priv->map, ASPEED_MCTP_RX_BUF_RD_PTR, &hw_read_ptr); -+ hw_read_ptr &= RX_BUF_RD_PTR_MASK; -+ regmap_write(priv->map, ASPEED_MCTP_RX_BUF_WR_PTR, (hw_read_ptr)); ++ /* These registers are write one to clear. Clear them. */ ++ for (i = 0; i < model->dr_num / 8; ++i) ++ aspeed_mbox_outb(mbox, 0xff, ASPEED_MBOX_STR(model->str, i)); + -+ dev_dbg(priv->dev, "RX hw ptr %02d, sw ptr %2d\n", -+ hw_read_ptr, rx->wr_ptr); -+ } else { -+ struct mctp_pcie_packet_data_2500 *rx_buf; ++ aspeed_mbox_outb(mbox, ASPEED_MBOX_BCR_RECV, model->bcr); ++ return 0; ++} + -+ rx_buf = (struct mctp_pcie_packet_data_2500 *)rx->data.vaddr; -+ payload = (u32 *)&rx_buf[rx->wr_ptr]; -+ rx_cmd = (struct aspeed_mctp_rx_cmd *)rx->cmd.vaddr; -+ hdr = (u32 *)&((rx_cmd + rx->wr_ptr)->rx_lo); ++static int aspeed_mbox_probe(struct platform_device *pdev) ++{ ++ struct aspeed_mbox *mbox; ++ struct device *dev; ++ int rc; + -+ if (!*hdr) { -+ u32 tmp_wr_ptr = rx->wr_ptr; ++ dev = &pdev->dev; + -+ /* -+ * HACK: Right after start the RX hardware can put received -+ * packet into an unexpected offset - in order to locate -+ * received packet driver has to scan all RX data buffers. -+ */ -+ do { -+ tmp_wr_ptr = (tmp_wr_ptr + 1) % rx->buffer_count; ++ mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); ++ if (!mbox) ++ return -ENOMEM; + -+ hdr = (u32 *)&((rx_cmd + tmp_wr_ptr)->rx_lo); -+ } while (!*hdr && tmp_wr_ptr != rx->wr_ptr); ++ dev_set_drvdata(&pdev->dev, mbox); + -+ if (tmp_wr_ptr != rx->wr_ptr) { -+ dev_warn(priv->dev, -+ "Runaway RX packet found %d -> %d\n", -+ rx->wr_ptr, tmp_wr_ptr); -+ rx->wr_ptr = tmp_wr_ptr; -+ } -+ } ++ rc = of_property_read_u32(dev->of_node, "reg", &mbox->base); ++ if (rc) { ++ dev_err(dev, "Couldn't read reg device tree property\n"); ++ return rc; ++ } + -+ while (*hdr != 0) { -+ rx_packet = aspeed_mctp_packet_alloc(GFP_ATOMIC); -+ if (rx_packet) { -+ memcpy(rx_packet->data.payload, payload, -+ sizeof(rx_packet->data.payload)); ++ mbox->model = of_device_get_match_data(dev); ++ if (IS_ERR(mbox->model)) { ++ dev_err(dev, "Couldn't get model data\n"); ++ return -ENODEV; ++ } + -+ aspeed_mctp_rx_hdr_prep(priv, (u8 *)rx_packet->data.hdr, *hdr); ++ mbox->map = syscon_node_to_regmap( ++ pdev->dev.parent->of_node); ++ if (IS_ERR(mbox->map)) { ++ dev_err(dev, "Couldn't get regmap\n"); ++ return -ENODEV; ++ } + -+ aspeed_mctp_swap_pcie_vdm_hdr(&rx_packet->data); ++ mutex_init(&mbox->mutex); ++ init_waitqueue_head(&mbox->queue); + -+ aspeed_mctp_dispatch_packet(priv, rx_packet); -+ } else { -+ dev_dbg(priv->dev, "Failed to allocate RX packet\n"); -+ } -+ dev_dbg(priv->dev, -+ "rx->wr_ptr = %d, rx_cmd->rx_lo = %08x", -+ rx->wr_ptr, *hdr); -+ data_dump(priv, &rx_packet->data); -+ *hdr = 0; -+ rx->wr_ptr = (rx->wr_ptr + 1) % rx->buffer_count; -+ payload = (u32 *)&rx_buf[rx->wr_ptr]; -+ hdr = (u32 *)&((rx_cmd + rx->wr_ptr)->rx_lo); -+ } ++ mbox->miscdev.minor = MISC_DYNAMIC_MINOR; ++ mbox->miscdev.name = DEVICE_NAME; ++ mbox->miscdev.fops = &aspeed_mbox_fops; ++ mbox->miscdev.parent = dev; ++ rc = misc_register(&mbox->miscdev); ++ if (rc) { ++ dev_err(dev, "Unable to register device\n"); ++ return rc; + } + -+ /* Kick RX if it was stopped due to ring full condition */ -+ if (rx->stopped) { -+ if (!rx_full) { -+ /* -+ * RX ring may still be full in here as the HW keeps producing when Tasklet consumes the packets. -+ * Use rx_full to detect if RX ring is already full before or after Tasklet consumption. -+ * Schedule another tasklet here to consume RX ring before restarting reception if ring is full after the while loop, -+ * in case that RX_CMD_NO_MORE_INT interrupts tasklet after tasklet consumes packets. -+ * Use flag cause we cannot control if ASPEED_MCTP_RX_BUF_WR_PTR can be updated before ring full occurs. -+ * Example of problematic scenario: -+ * 1. Tasklet executing, found *hdr==0 at wr_ptr=14, break the while loop and going forward. -+ * 2. After leaving the loop, Tasklet spend time doing some time-consuming stuffs like printing log. -+ * 3. HW keep receiving during step2, and triggered RX_CMD_NO_MORE_INT to set rx->stopped to true in the IRQ handler. -+ * 4. CPU returns to Tasklet, after step2 the tasklet sees rx->stopped == true, therefore kick RX_READY to restart RX. -+ * 5. Issue reproduced, RX restarted without stored packets consumed, and get overwritten later. -+ */ -+ tasklet_hi_schedule(&priv->rx.tasklet); -+ } else { -+ rx->stopped = false; -+ regmap_update_bits(priv->map, ASPEED_MCTP_CTRL, RX_CMD_READY, -+ RX_CMD_READY); -+ } ++ rc = aspeed_mbox_config_irq(mbox, pdev); ++ if (rc) { ++ dev_err(dev, "Failed to configure IRQ\n"); ++ misc_deregister(&mbox->miscdev); ++ return rc; + } ++ ++ return 0; +} + -+static void aspeed_mctp_rx_chan_init(struct mctp_channel *rx) ++static void aspeed_mbox_remove(struct platform_device *pdev) +{ -+ struct aspeed_mctp *priv = container_of(rx, typeof(*priv), rx); -+ u32 *rx_cmd = (u32 *)rx->cmd.vaddr; -+ struct aspeed_mctp_rx_cmd *rx_cmd_64 = -+ (struct aspeed_mctp_rx_cmd *)rx->cmd.vaddr; -+ u32 data_size = priv->match_data->packet_unit_size; -+ u32 hw_rx_count = priv->rx_packet_count; -+ struct mctp_pcie_packet_data *rx_buf = (struct mctp_pcie_packet_data *)rx->data.vaddr; -+ int i; ++ struct aspeed_mbox *mbox = dev_get_drvdata(&pdev->dev); + -+ if (priv->match_data->vdm_hdr_direct_xfer) { -+ if (priv->match_data->dma_need_64bits_width) { -+ for (i = 0; i < priv->rx_packet_count; i++) { -+ rx_cmd_64->rx_hi = -+ upper_32_bits((rx->data.dma_handle + data_size * i)); -+ rx_cmd_64->rx_lo = -+ (rx->data.dma_handle + data_size * i) & -+ GENMASK(31, 4); -+ rx_cmd_64->rx_lo |= RX_INTERRUPT_AFTER_CMD; -+ rx_cmd_64++; -+ } -+ } else { -+ for (i = 0; i < priv->rx_packet_count; i++) { -+ *rx_cmd = RX_DATA_ADDR(rx->data.dma_handle + data_size * i); -+ *rx_cmd |= RX_INTERRUPT_AFTER_CMD; -+ rx_cmd++; -+ } -+ } -+ } else { -+ for (i = 0; i < priv->rx_packet_count; i++) { -+ rx_cmd_64->rx_hi = RX_DATA_ADDR_2500(rx->data.dma_handle + data_size * i); -+ rx_cmd_64->rx_lo = 0; -+ if (i == priv->rx_packet_count - 1) -+ rx_cmd_64->rx_hi |= RX_LAST_CMD; -+ rx_cmd_64++; -+ } -+ } -+ /* Clear the header of rx data */ -+ for (i = 0; i < priv->rx_packet_count; i++) -+ *(u32 *)&rx_buf[i] = 0; -+ rx->wr_ptr = 0; -+ rx->buffer_count = priv->rx_packet_count; -+ if (priv->match_data->fifo_auto_surround) { -+ /* -+ * TODO: Once read pointer runaway bug is fixed in some future AST2x00 -+ * stepping then add chip revision detection and turn on this -+ * workaround only when needed -+ */ -+ if (priv->match_data->dma_need_64bits_width) -+ priv->rx_runaway_wa.enable = false; -+ else -+ priv->rx_runaway_wa.enable = -+ (chip_version(priv->dev) == ASPEED_MCTP_2600) ? -+ true : -+ false; ++ misc_deregister(&mbox->miscdev); ++} + -+ /* -+ * Hardware does not wrap around ASPEED_MCTP_RX_BUF_SIZE -+ * correctly - we have to set number of buffers to n/4 -1 -+ */ -+ if (priv->rx_runaway_wa.enable) -+ hw_rx_count = (priv->rx_packet_count / 4 - 1); ++static const struct aspeed_mbox_model ast2400_model = { ++ .dr_num = 16, ++ .dr = 0x0, ++ .str = 0x40, ++ .bcr = 0x48, ++ .hcr = 0x4c, ++ .bie = 0x50, ++ .hie = 0x58, ++}; + -+ regmap_write(priv->map, ASPEED_MCTP_RX_BUF_SIZE, hw_rx_count); -+ } -+} ++static const struct aspeed_mbox_model ast2600_model = { ++ .dr_num = 32, ++ .dr = 0x0, ++ .str = 0x80, ++ .bcr = 0x90, ++ .hcr = 0x94, ++ .bie = 0xa0, ++ .hie = 0xb0, ++}; + -+static void aspeed_mctp_tx_chan_init(struct mctp_channel *tx) -+{ -+ struct aspeed_mctp *priv = container_of(tx, typeof(*priv), tx); ++static const struct of_device_id aspeed_mbox_match[] = { ++ { .compatible = "aspeed,ast2400-mbox", ++ .data = &ast2400_model }, ++ { .compatible = "aspeed,ast2500-mbox", ++ .data = &ast2400_model }, ++ { .compatible = "aspeed,ast2600-mbox", ++ .data = &ast2600_model }, ++ { }, ++}; + -+ tx->wr_ptr = 0; -+ tx->rd_ptr = 0; -+ regmap_update_bits(priv->map, ASPEED_MCTP_CTRL, TX_CMD_TRIGGER, 0); -+ regmap_write(priv->map, ASPEED_MCTP_TX_BUF_ADDR, tx->cmd.dma_handle); -+ if (priv->match_data->dma_need_64bits_width) -+ regmap_write(priv->map, ASPEED_MCTP_TX_BUF_HI_ADDR, -+ upper_32_bits(tx->cmd.dma_handle)); -+ if (priv->match_data->fifo_auto_surround) { -+ regmap_write(priv->map, ASPEED_MCTP_TX_BUF_SIZE, TX_PACKET_COUNT); -+ regmap_write(priv->map, ASPEED_MCTP_TX_BUF_WR_PTR, 0); -+ } -+} ++static struct platform_driver aspeed_mbox_driver = { ++ .driver = { ++ .name = DEVICE_NAME, ++ .of_match_table = aspeed_mbox_match, ++ }, ++ .probe = aspeed_mbox_probe, ++ .remove = aspeed_mbox_remove, ++}; + -+struct mctp_client *aspeed_mctp_create_client(struct aspeed_mctp *priv) -+{ -+ struct mctp_client *client; ++module_platform_driver(aspeed_mbox_driver); ++MODULE_DEVICE_TABLE(of, aspeed_mbox_match); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Cyril Bur "); ++MODULE_AUTHOR("Chia-Wei Wang ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ client = aspeed_mctp_client_alloc(priv); -+ if (!client) -+ return NULL; ++#define DEVICE_NAME "aspeed-lpc-pcc" + -+ init_waitqueue_head(&client->wait_queue); ++static DEFINE_IDA(aspeed_pcc_ida); + -+ spin_lock_bh(&priv->clients_lock); -+ list_add_tail(&client->link, &priv->clients); -+ spin_unlock_bh(&priv->clients_lock); ++#define HICR5 0x80 ++#define HICR5_EN_SNP0W BIT(0) ++#define HICR5_EN_SNP1W BIT(2) ++#define HICR6 0x084 ++#define HICR6_EN2BMODE BIT(19) ++#define SNPWADR 0x090 ++#define PCCR6 0x0c4 ++#define PCCR6_DMA_CUR_ADDR GENMASK(27, 0) ++#define PCCR4 0x0d0 ++#define PCCR4_DMA_ADDRL_MASK GENMASK(31, 0) ++#define PCCR4_DMA_ADDRL_SHIFT 0 ++#define PCCR5 0x0d4 ++#define PCCR5_DMA_ADDRH_MASK GENMASK(27, 24) ++#define PCCR5_DMA_ADDRH_SHIFT 24 ++#define PCCR5_DMA_LEN_MASK GENMASK(23, 0) ++#define PCCR5_DMA_LEN_SHIFT 0 ++#define HICRB 0x100 ++#define HICRB_ENSNP0D BIT(14) ++#define HICRB_ENSNP1D BIT(15) ++#define PCCR0 0x130 ++#define PCCR0_EN_DMA_INT BIT(31) ++#define PCCR0_EN_DMA_MODE BIT(14) ++#define PCCR0_ADDR_SEL_MASK GENMASK(13, 12) ++#define PCCR0_ADDR_SEL_SHIFT 12 ++#define PCCR0_RX_TRIG_LVL_MASK GENMASK(10, 8) ++#define PCCR0_RX_TRIG_LVL_SHIFT 8 ++#define PCCR0_CLR_RX_FIFO BIT(7) ++#define PCCR0_MODE_SEL_MASK GENMASK(5, 4) ++#define PCCR0_MODE_SEL_SHIFT 4 ++#define PCCR0_EN_RX_TMOUT_INT BIT(2) ++#define PCCR0_EN_RX_AVAIL_INT BIT(1) ++#define PCCR0_EN BIT(0) ++#define PCCR1 0x134 ++#define PCCR1_BASE_ADDR_MASK GENMASK(15, 0) ++#define PCCR1_BASE_ADDR_SHIFT 0 ++#define PCCR1_DONT_CARE_BITS_MASK GENMASK(21, 16) ++#define PCCR1_DONT_CARE_BITS_SHIFT 16 ++#define PCCR2 0x138 ++#define PCCR2_INT_STATUS_PATTERN_B BIT(16) ++#define PCCR2_INT_STATUS_PATTERN_A BIT(8) ++#define PCCR2_INT_STATUS_DMA_DONE BIT(4) ++#define PCCR2_INT_STATUS_DATA_RDY PCCR2_INT_STATUS_DMA_DONE ++#define PCCR2_INT_STATUS_RX_OVER BIT(3) ++#define PCCR2_INT_STATUS_RX_TMOUT BIT(2) ++#define PCCR2_INT_STATUS_RX_AVAIL BIT(1) ++#define PCCR3 0x13c ++#define PCCR3_FIFO_DATA_MASK GENMASK(7, 0) ++ ++#define PCC_DMA_BUFSZ (256 * SZ_1K) ++ ++enum pcc_fifo_threshold { ++ PCC_FIFO_THR_1_BYTE, ++ PCC_FIFO_THR_1_EIGHTH, ++ PCC_FIFO_THR_2_EIGHTH, ++ PCC_FIFO_THR_3_EIGHTH, ++ PCC_FIFO_THR_4_EIGHTH, ++ PCC_FIFO_THR_5_EIGHTH, ++ PCC_FIFO_THR_6_EIGHTH, ++ PCC_FIFO_THR_7_EIGHTH, ++ PCC_FIFO_THR_8_EIGHTH, ++}; ++ ++enum pcc_record_mode { ++ PCC_REC_1B, ++ PCC_REC_2B, ++ PCC_REC_4B, ++ PCC_REC_FULL, ++}; ++ ++enum pcc_port_hbits_select { ++ PCC_PORT_HBITS_SEL_NONE, ++ PCC_PORT_HBITS_SEL_45, ++ PCC_PORT_HBITS_SEL_67, ++ PCC_PORT_HBITS_SEL_89, ++}; ++ ++struct aspeed_pcc_dma { ++ uint32_t rptr; ++ uint8_t *virt; ++ dma_addr_t addr; ++ uint32_t size; ++}; ++ ++struct aspeed_pcc_ctrl { ++ struct device *dev; ++ struct regmap *regmap; ++ int irq; ++ uint32_t port; ++ struct aspeed_pcc_dma dma; ++ struct kfifo fifo; ++ wait_queue_head_t wq; ++ struct miscdevice mdev; ++ int mdev_id; ++}; + -+ return client; ++static inline bool is_valid_rec_mode(uint32_t mode) ++{ ++ return (mode > PCC_REC_FULL) ? false : true; +} -+EXPORT_SYMBOL_GPL(aspeed_mctp_create_client); + -+static int aspeed_mctp_open(struct inode *inode, struct file *file) ++static inline bool is_valid_high_bits_select(uint32_t sel) +{ -+ struct miscdevice *misc = file->private_data; -+ struct platform_device *pdev = to_platform_device(misc->parent); -+ struct aspeed_mctp *priv = platform_get_drvdata(pdev); -+ struct mctp_client *client; -+ -+ client = aspeed_mctp_create_client(priv); -+ if (!client) -+ return -ENOMEM; -+ -+ file->private_data = client; -+ -+ return 0; ++ return (sel > PCC_PORT_HBITS_SEL_89) ? false : true; +} + -+void aspeed_mctp_delete_client(struct mctp_client *client) ++static ssize_t aspeed_pcc_file_read(struct file *file, char __user *buffer, ++ size_t count, loff_t *ppos) +{ -+ struct aspeed_mctp *priv = client->priv; -+ struct mctp_type_handler *handler, *tmp; -+ -+ spin_lock_bh(&priv->clients_lock); -+ -+ list_del(&client->link); ++ int rc; ++ unsigned int copied; ++ struct aspeed_pcc_ctrl *pcc = container_of(file->private_data, ++ struct aspeed_pcc_ctrl, ++ mdev); + -+ if (priv->default_client == client) -+ priv->default_client = NULL; ++ if (kfifo_is_empty(&pcc->fifo)) { ++ if (file->f_flags & O_NONBLOCK) ++ return -EAGAIN; + -+ list_for_each_entry_safe(handler, tmp, &priv->mctp_type_handlers, -+ link) { -+ if (handler->client == client) { -+ list_del(&handler->link); -+ kfree(handler); -+ } ++ rc = wait_event_interruptible(pcc->wq, ++ !kfifo_is_empty(&pcc->fifo)); ++ if (rc == -ERESTARTSYS) ++ return -EINTR; + } -+ spin_unlock_bh(&priv->clients_lock); + -+ /* Disable the tasklet to appease lockdep */ -+ local_bh_disable(); -+ aspeed_mctp_client_put(client); -+ local_bh_enable(); ++ rc = kfifo_to_user(&pcc->fifo, buffer, count, &copied); ++ ++ return rc ? rc : copied; +} -+EXPORT_SYMBOL_GPL(aspeed_mctp_delete_client); + -+static int aspeed_mctp_release(struct inode *inode, struct file *file) ++static __poll_t aspeed_pcc_file_poll(struct file *file, ++ struct poll_table_struct *pt) +{ -+ struct mctp_client *client = file->private_data; ++ struct aspeed_pcc_ctrl *pcc = container_of(file->private_data, ++ struct aspeed_pcc_ctrl, ++ mdev); + -+ aspeed_mctp_delete_client(client); ++ poll_wait(file, &pcc->wq, pt); + -+ return 0; ++ return !kfifo_is_empty(&pcc->fifo) ? POLLIN : 0; +} + -+#define LEN_MASK_HI GENMASK(9, 8) -+#define LEN_MASK_LO GENMASK(7, 0) -+#define PCI_VDM_HDR_LEN_MASK_LO GENMASK(31, 24) -+#define PCI_VDM_HDR_LEN_MASK_HI GENMASK(17, 16) -+#define PCIE_VDM_HDR_REQUESTER_BDF_MASK GENMASK(31, 16) ++static const struct file_operations pcc_fops = { ++ .owner = THIS_MODULE, ++ .read = aspeed_pcc_file_read, ++ .poll = aspeed_pcc_file_poll, ++}; + -+int aspeed_mctp_send_packet(struct mctp_client *client, -+ struct mctp_pcie_packet *packet) ++static irqreturn_t aspeed_pcc_dma_isr(int irq, void *arg) +{ -+ struct aspeed_mctp *priv = client->priv; -+ u32 *hdr_dw = (u32 *)packet->data.hdr; -+ u8 *hdr = (u8 *)packet->data.hdr; -+ u8 *payload = (u8 *)packet->data.payload; -+ u16 packet_data_sz_dw; -+ u16 pci_data_len_dw; -+ int ret; -+ u16 bdf; ++ uint32_t reg, rptr, wptr; ++ struct aspeed_pcc_ctrl *pcc = (struct aspeed_pcc_ctrl *)arg; ++ struct kfifo *fifo = &pcc->fifo; + -+ ret = _get_bdf(priv); -+ if (ret < 0) -+ return ret; -+ bdf = ret; ++ regmap_write_bits(pcc->regmap, PCCR2, PCCR2_INT_STATUS_DMA_DONE, PCCR2_INT_STATUS_DMA_DONE); + -+ /* -+ * If the data size is different from contents of PCIe VDM header, -+ * aspeed_mctp_tx_cmd will be programmed incorrectly. This may cause -+ * MCTP HW to stop working. -+ */ -+ pci_data_len_dw = FIELD_PREP(LEN_MASK_LO, FIELD_GET(PCI_VDM_HDR_LEN_MASK_LO, hdr_dw[0])) | -+ FIELD_PREP(LEN_MASK_HI, FIELD_GET(PCI_VDM_HDR_LEN_MASK_HI, hdr_dw[0])); -+ if (pci_data_len_dw == 0) /* According to PCIe Spec, 0 means 1024 DW */ -+ pci_data_len_dw = SZ_1K; ++ regmap_read(pcc->regmap, PCCR6, ®); ++ wptr = (reg & PCCR6_DMA_CUR_ADDR) - (pcc->dma.addr & PCCR6_DMA_CUR_ADDR); ++ rptr = pcc->dma.rptr; + -+ packet_data_sz_dw = packet->size / sizeof(u32) - sizeof(packet->data.hdr) / sizeof(u32); -+ if (packet_data_sz_dw != pci_data_len_dw) -+ return -EINVAL; ++ do { ++ if (kfifo_is_full(fifo)) ++ kfifo_skip(fifo); + -+ be32p_replace_bits(&hdr_dw[1], bdf, PCIE_VDM_HDR_REQUESTER_BDF_MASK); ++ kfifo_put(fifo, pcc->dma.virt[rptr]); + -+ /* -+ * XXX Don't update EID for MCTP Control messages - old EID may -+ * interfere with MCTP discovery flow. -+ */ -+ if (priv->eid && payload[MCTP_PAYLOAD_TYPE_OFFSET] != MCTP_HDR_TYPE_CONTROL) -+ hdr[MCTP_HDR_SRC_EID_OFFSET] = priv->eid; ++ rptr = (rptr + 1) % pcc->dma.size; ++ } while (rptr != wptr); + -+ ret = ptr_ring_produce_bh(&client->tx_queue, packet); -+ if (!ret) -+ tasklet_hi_schedule(&priv->tx.tasklet); ++ pcc->dma.rptr = rptr; + -+ return ret; ++ wake_up_interruptible(&pcc->wq); ++ ++ return IRQ_HANDLED; +} -+EXPORT_SYMBOL_GPL(aspeed_mctp_send_packet); + -+struct mctp_pcie_packet *aspeed_mctp_receive_packet(struct mctp_client *client, -+ unsigned long timeout) ++static irqreturn_t aspeed_pcc_isr(int irq, void *arg) +{ -+ struct aspeed_mctp *priv = client->priv; -+ int ret; ++ uint32_t sts; ++ struct aspeed_pcc_ctrl *pcc = (struct aspeed_pcc_ctrl *)arg; + -+ ret = _get_bdf(priv); -+ if (ret < 0) -+ return ERR_PTR(ret); ++ regmap_read(pcc->regmap, PCCR2, &sts); + -+ 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 (!(sts & (PCCR2_INT_STATUS_RX_TMOUT | ++ PCCR2_INT_STATUS_RX_AVAIL | ++ PCCR2_INT_STATUS_DMA_DONE))) ++ return IRQ_NONE; + -+ return ptr_ring_consume_bh(&client->rx_queue); ++ return aspeed_pcc_dma_isr(irq, arg); +} -+EXPORT_SYMBOL_GPL(aspeed_mctp_receive_packet); + -+void aspeed_mctp_flush_rx_queue(struct mctp_client *client) ++/* ++ * A2600-15 AP note ++ * ++ * SW workaround to prevent generating Non-Fatal-Error (NFE) ++ * eSPI response when PCC is used for port I/O byte snooping ++ * over eSPI. ++ */ ++static int aspeed_a2600_15(struct aspeed_pcc_ctrl *pcc, struct device *dev) +{ -+ struct mctp_pcie_packet *packet; ++ u32 hicr5_en, hicrb_en; + -+ while ((packet = ptr_ring_consume_bh(&client->rx_queue))) -+ aspeed_mctp_packet_free(packet); ++ /* abort if snoop is enabled */ ++ regmap_read(pcc->regmap, HICR5, &hicr5_en); ++ if (hicr5_en & (HICR5_EN_SNP0W | HICR5_EN_SNP1W)) { ++ dev_err(dev, "A2600-15 should be applied with snoop disabled\n"); ++ return -EPERM; ++ } ++ ++ /* set SNPWADR of snoop device */ ++ regmap_write(pcc->regmap, SNPWADR, pcc->port | ((pcc->port + 2) << 16)); ++ ++ /* set HICRB[15:14]=11b to enable ACCEPT response for SNPWADR */ ++ hicrb_en = HICRB_ENSNP0D | HICRB_ENSNP1D; ++ regmap_update_bits(pcc->regmap, HICRB, hicrb_en, hicrb_en); ++ ++ /* set HICR6[19] to extend SNPWADR to 2x range */ ++ regmap_update_bits(pcc->regmap, HICR6, HICR6_EN2BMODE, HICR6_EN2BMODE); ++ ++ return 0; +} -+EXPORT_SYMBOL_GPL(aspeed_mctp_flush_rx_queue); + -+static ssize_t aspeed_mctp_read(struct file *file, char __user *buf, -+ size_t count, loff_t *ppos) ++static int aspeed_pcc_enable(struct aspeed_pcc_ctrl *pcc, struct device *dev) +{ -+ struct mctp_client *client = file->private_data; -+ struct aspeed_mctp *priv = client->priv; -+ struct mctp_pcie_packet *rx_packet; -+ u32 mctp_ctrl; -+ u32 mctp_int_sts; ++ int rc; + -+ if (count < PCIE_MCTP_MIN_PACKET_SIZE) -+ return -EINVAL; ++ rc = aspeed_a2600_15(pcc, dev); ++ if (rc) ++ return rc; + -+ if (count > sizeof(rx_packet->data)) -+ count = sizeof(rx_packet->data); ++ /* record mode: Set 2-Byte mode. */ ++ regmap_update_bits(pcc->regmap, PCCR0, ++ PCCR0_MODE_SEL_MASK, ++ PCC_REC_2B << PCCR0_MODE_SEL_SHIFT); + -+ if (priv->miss_mctp_int) { -+ regmap_read(priv->map, ASPEED_MCTP_CTRL, &mctp_ctrl); -+ if (!(mctp_ctrl & RX_CMD_READY)) -+ priv->rx.stopped = true; -+ /* Polling the RX_CMD_RECEIVE_INT to ensure rx_tasklet can find the data */ -+ regmap_read(priv->map, ASPEED_MCTP_INT_STS, &mctp_int_sts); -+ if (mctp_int_sts & RX_CMD_RECEIVE_INT) -+ regmap_write(priv->map, ASPEED_MCTP_INT_STS, -+ mctp_int_sts); -+ } ++ /* port address */ ++ regmap_update_bits(pcc->regmap, PCCR1, ++ PCCR1_BASE_ADDR_MASK, ++ pcc->port << PCCR1_BASE_ADDR_SHIFT); + -+ tasklet_hi_schedule(&priv->rx.tasklet); -+ rx_packet = ptr_ring_consume_bh(&client->rx_queue); -+ if (!rx_packet) -+ return -EAGAIN; ++ /* Set address high bits selection to 0b01 for address bit[5:4] */ ++ regmap_update_bits(pcc->regmap, PCCR0, ++ PCCR0_ADDR_SEL_MASK, ++ PCC_PORT_HBITS_SEL_45 << PCCR0_ADDR_SEL_SHIFT); + -+ if (copy_to_user(buf, &rx_packet->data, count)) { -+ dev_err(priv->dev, "copy to user failed\n"); -+ count = -EFAULT; -+ } ++ /* Set LPC don't care address to 0x3 for port 80~83h */ ++ regmap_update_bits(pcc->regmap, PCCR1, ++ PCCR1_DONT_CARE_BITS_MASK, ++ 0x3 << PCCR1_DONT_CARE_BITS_SHIFT); + -+ aspeed_mctp_packet_free(rx_packet); ++ /* set DMA ring buffer size and enable interrupts */ ++ regmap_write(pcc->regmap, PCCR4, pcc->dma.addr & 0xffffffff); ++#ifdef CONFIG_ARM64 ++ regmap_update_bits(pcc->regmap, PCCR5, PCCR5_DMA_ADDRH_MASK, ++ (pcc->dma.addr >> 32) << PCCR5_DMA_ADDRH_SHIFT); ++#endif ++ regmap_update_bits(pcc->regmap, PCCR5, PCCR5_DMA_LEN_MASK, ++ (pcc->dma.size / 4) << PCCR5_DMA_LEN_SHIFT); ++ regmap_update_bits(pcc->regmap, PCCR0, ++ PCCR0_EN_DMA_INT | PCCR0_EN_DMA_MODE, ++ PCCR0_EN_DMA_INT | PCCR0_EN_DMA_MODE); + -+ return count; ++ regmap_update_bits(pcc->regmap, PCCR0, PCCR0_EN, PCCR0_EN); ++ ++ return 0; +} + -+static void aspeed_mctp_flush_tx_queue(struct mctp_client *client) ++static int aspeed_pcc_disable(struct aspeed_pcc_ctrl *pcc) +{ -+ struct mctp_pcie_packet *packet; ++ /* Disable PCC and DMA Mode for safety */ ++ regmap_update_bits(pcc->regmap, PCCR0, PCCR0_EN | PCCR0_EN_DMA_MODE, 0); + -+ while ((packet = ptr_ring_consume_bh(&client->tx_queue))) -+ aspeed_mctp_packet_free(packet); -+} ++ /* Clear Rx FIFO. */ ++ regmap_update_bits(pcc->regmap, PCCR0, PCCR0_CLR_RX_FIFO, 1); + -+static void aspeed_mctp_flush_all_tx_queues(struct aspeed_mctp *priv) -+{ -+ struct mctp_client *client; ++ /* Clear All interrupts status. */ ++ regmap_write(pcc->regmap, PCCR2, ++ PCCR2_INT_STATUS_RX_OVER | PCCR2_INT_STATUS_DMA_DONE | ++ PCCR2_INT_STATUS_PATTERN_A | PCCR2_INT_STATUS_PATTERN_B); + -+ spin_lock_bh(&priv->clients_lock); -+ list_for_each_entry(client, &priv->clients, link) -+ aspeed_mctp_flush_tx_queue(client); -+ spin_unlock_bh(&priv->clients_lock); ++ return 0; +} + -+static ssize_t aspeed_mctp_write(struct file *file, const char __user *buf, -+ size_t count, loff_t *ppos) ++static int aspeed_pcc_probe(struct platform_device *pdev) +{ -+ struct mctp_client *client = file->private_data; -+ struct aspeed_mctp *priv = client->priv; -+ struct mctp_pcie_packet *tx_packet; -+ int ret; ++ int rc; ++ struct aspeed_pcc_ctrl *pcc; ++ struct device *dev = &pdev->dev; ++ uint32_t fifo_size = PAGE_SIZE; + -+ if (count < PCIE_MCTP_MIN_PACKET_SIZE) -+ return -EINVAL; ++ pcc = devm_kzalloc(dev, sizeof(*pcc), GFP_KERNEL); ++ if (!pcc) ++ return -ENOMEM; + -+ if (count > sizeof(tx_packet->data)) -+ return -ENOSPC; ++ pcc->regmap = syscon_node_to_regmap(dev->parent->of_node); ++ if (IS_ERR(pcc->regmap)) ++ return dev_err_probe(dev, PTR_ERR(pcc->regmap), "Couldn't get regmap\n"); + -+ tx_packet = aspeed_mctp_packet_alloc(GFP_KERNEL); -+ if (!tx_packet) { -+ ret = -ENOMEM; -+ goto out; ++ rc = of_property_read_u32(dev->of_node, "pcc-ports", &pcc->port); ++ if (rc) { ++ dev_err(dev, "no pcc ports configured\n"); ++ return rc; + } + -+ if (copy_from_user(&tx_packet->data, buf, count)) { -+ dev_err(priv->dev, "copy from user failed\n"); -+ ret = -EFAULT; -+ goto out_packet; ++ 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; + } + -+ tx_packet->size = count; -+ -+ ret = aspeed_mctp_send_packet(client, tx_packet); -+ if (ret) -+ goto out_packet; -+ -+ return count; -+ -+out_packet: -+ aspeed_mctp_packet_free(tx_packet); -+out: -+ return ret; -+} ++ pcc->dma.size = PCC_DMA_BUFSZ; ++ pcc->dma.virt = dmam_alloc_coherent(dev, ++ pcc->dma.size, ++ &pcc->dma.addr, ++ GFP_KERNEL); ++ if (!pcc->dma.virt) { ++ dev_err(dev, "cannot allocate DMA buffer\n"); ++ return -ENOMEM; ++ } + -+int aspeed_mctp_add_type_handler(struct mctp_client *client, u8 mctp_type, -+ u16 pci_vendor_id, u16 vdm_type, u16 vdm_mask) -+{ -+ struct aspeed_mctp *priv = client->priv; -+ struct mctp_type_handler *handler, *new_handler; -+ int ret = 0; ++ fifo_size = roundup(pcc->dma.size, PAGE_SIZE); ++ rc = kfifo_alloc(&pcc->fifo, fifo_size, GFP_KERNEL); ++ if (rc) ++ return rc; + -+ if (mctp_type <= MCTP_HDR_TYPE_BASE_LAST) { -+ /* Vendor, type and type mask must be zero for types 0-5 */ -+ if (pci_vendor_id != 0 || vdm_type != 0 || vdm_mask != 0) -+ return -EINVAL; -+ } else if (mctp_type == MCTP_HDR_TYPE_VDM_PCI) { -+ /* For Vendor Defined PCI type the vendor ID must be nonzero */ -+ if (pci_vendor_id == 0 || pci_vendor_id == 0xffff) -+ return -EINVAL; -+ } else { -+ return -EINVAL; ++ /* Disable PCC to clean up DMA buffer before request IRQ. */ ++ rc = aspeed_pcc_disable(pcc); ++ if (rc) { ++ dev_err(dev, "Couldn't disable PCC\n"); ++ goto err_free_kfifo; + } + -+ new_handler = kzalloc(sizeof(*new_handler), GFP_KERNEL); -+ if (!new_handler) -+ return -ENOMEM; -+ new_handler->mctp_type = mctp_type; -+ new_handler->pci_vendor_id = pci_vendor_id; -+ new_handler->vdm_type = vdm_type & vdm_mask; -+ new_handler->vdm_mask = vdm_mask; -+ new_handler->client = client; ++ pcc->irq = platform_get_irq(pdev, 0); ++ if (pcc->irq < 0) { ++ rc = pcc->irq; ++ goto err_free_kfifo; ++ } + -+ spin_lock_bh(&priv->clients_lock); -+ list_for_each_entry(handler, &priv->mctp_type_handlers, link) { -+ if (handler->mctp_type == new_handler->mctp_type && -+ handler->pci_vendor_id == new_handler->pci_vendor_id && -+ handler->vdm_type == new_handler->vdm_type) { -+ if (handler->client != new_handler->client) -+ ret = -EBUSY; -+ kfree(new_handler); -+ goto out_unlock; -+ } ++ rc = devm_request_irq(dev, pcc->irq, aspeed_pcc_isr, 0, DEVICE_NAME, pcc); ++ if (rc < 0) { ++ dev_err(dev, "Couldn't request IRQ %d\n", pcc->irq); ++ goto err_free_kfifo; + } -+ list_add_tail(&new_handler->link, &priv->mctp_type_handlers); -+out_unlock: -+ spin_unlock_bh(&priv->clients_lock); + -+ return ret; -+} -+EXPORT_SYMBOL_GPL(aspeed_mctp_add_type_handler); ++ init_waitqueue_head(&pcc->wq); + -+static int aspeed_mctp_remove_type_handler(struct mctp_client *client, -+ u8 mctp_type, u16 pci_vendor_id, -+ u16 vdm_type, u16 vdm_mask) -+{ -+ struct aspeed_mctp *priv = client->priv; -+ struct mctp_type_handler *handler, *tmp; -+ int ret = -EINVAL; ++ pcc->mdev_id = ida_alloc(&aspeed_pcc_ida, GFP_KERNEL); ++ if (pcc->mdev_id < 0) { ++ dev_err(dev, "Couldn't allocate ID\n"); ++ goto err_free_kfifo; ++ } + -+ vdm_type &= vdm_mask; ++ pcc->mdev.parent = dev; ++ pcc->mdev.minor = MISC_DYNAMIC_MINOR; ++ pcc->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s%d", DEVICE_NAME, ++ pcc->mdev_id); ++ pcc->mdev.fops = &pcc_fops; ++ rc = misc_register(&pcc->mdev); ++ if (rc) { ++ dev_err(dev, "Couldn't register misc device\n"); ++ goto err_free_ida; ++ } + -+ spin_lock_bh(&priv->clients_lock); -+ list_for_each_entry_safe(handler, tmp, &priv->mctp_type_handlers, -+ link) { -+ if (handler->client == client && -+ handler->mctp_type == mctp_type && -+ handler->pci_vendor_id == pci_vendor_id && -+ handler->vdm_type == vdm_type) { -+ list_del(&handler->link); -+ kfree(handler); -+ ret = 0; -+ break; -+ } ++ rc = aspeed_pcc_enable(pcc, dev); ++ if (rc) { ++ dev_err(dev, "Couldn't enable PCC\n"); ++ goto err_dereg_mdev; + } -+ spin_unlock_bh(&priv->clients_lock); -+ return ret; -+} + -+int aspeed_mctp_register_default_handler(struct mctp_client *client) -+{ -+ struct aspeed_mctp *priv = client->priv; -+ int ret = 0; ++ dev_set_drvdata(dev, pcc); + -+ spin_lock_bh(&priv->clients_lock); ++ return 0; + -+ if (!priv->default_client) -+ priv->default_client = client; -+ else if (priv->default_client != client) -+ ret = -EBUSY; ++err_dereg_mdev: ++ misc_deregister(&pcc->mdev); + -+ spin_unlock_bh(&priv->clients_lock); ++err_free_ida: ++ ida_free(&aspeed_pcc_ida, pcc->mdev_id); + -+ return ret; ++err_free_kfifo: ++ kfifo_free(&pcc->fifo); ++ ++ return rc; +} -+EXPORT_SYMBOL_GPL(aspeed_mctp_register_default_handler); + -+static int -+aspeed_mctp_register_type_handler(struct mctp_client *client, -+ void __user *userbuf) ++static void aspeed_pcc_remove(struct platform_device *pdev) +{ -+ struct aspeed_mctp *priv = client->priv; -+ struct aspeed_mctp_type_handler_ioctl handler; -+ -+ if (copy_from_user(&handler, userbuf, sizeof(handler))) { -+ dev_err(priv->dev, "copy from user failed\n"); -+ return -EFAULT; -+ } ++ struct device *dev = &pdev->dev; ++ struct aspeed_pcc_ctrl *pcc = dev_get_drvdata(dev); + -+ return aspeed_mctp_add_type_handler(client, handler.mctp_type, -+ handler.pci_vendor_id, -+ handler.vendor_type, -+ handler.vendor_type_mask); ++ kfifo_free(&pcc->fifo); ++ ida_free(&aspeed_pcc_ida, pcc->mdev_id); ++ misc_deregister(&pcc->mdev); +} + -+static int -+aspeed_mctp_unregister_type_handler(struct mctp_client *client, -+ void __user *userbuf) -+{ -+ struct aspeed_mctp *priv = client->priv; -+ struct aspeed_mctp_type_handler_ioctl handler; ++static const struct of_device_id aspeed_pcc_table[] = { ++ { .compatible = "aspeed,ast2600-lpc-pcc" }, ++ { }, ++}; + -+ if (copy_from_user(&handler, userbuf, sizeof(handler))) { -+ dev_err(priv->dev, "copy from user failed\n"); -+ return -EFAULT; -+ } ++static struct platform_driver aspeed_pcc_driver = { ++ .driver = { ++ .name = "aspeed-pcc", ++ .of_match_table = aspeed_pcc_table, ++ }, ++ .probe = aspeed_pcc_probe, ++ .remove = aspeed_pcc_remove, ++}; ++ ++module_platform_driver(aspeed_pcc_driver); ++ ++MODULE_AUTHOR("Chia-Wei Wang "); ++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 +@@ -11,7 +11,7 @@ + */ + + #include +-#include ++#include + #include + #include + #include +@@ -25,7 +25,6 @@ + + #define DEVICE_NAME "aspeed-lpc-snoop" + +-#define NUM_SNOOP_CHANNELS 2 + #define SNOOP_FIFO_SIZE 2048 + + #define HICR5 0x80 +@@ -36,6 +35,7 @@ + #define HICR6 0x84 + #define HICR6_STR_SNP0W BIT(0) + #define HICR6_STR_SNP1W BIT(1) ++#define HICR6_NFE_WA BIT(20) + #define SNPWADR 0x90 + #define SNPWADR_CH0_MASK GENMASK(15, 0) + #define SNPWADR_CH0_SHIFT 0 +@@ -57,7 +57,22 @@ + unsigned int has_hicrb_ensnp; + }; + ++enum aspeed_lpc_snoop_index { ++ ASPEED_LPC_SNOOP_INDEX_0 = 0, ++ ASPEED_LPC_SNOOP_INDEX_1 = 1, ++ ASPEED_LPC_SNOOP_INDEX_MAX = ASPEED_LPC_SNOOP_INDEX_1, ++}; + -+ return aspeed_mctp_remove_type_handler(client, handler.mctp_type, -+ handler.pci_vendor_id, -+ handler.vendor_type, -+ handler.vendor_type_mask); -+} ++struct aspeed_lpc_snoop_channel_cfg { ++ enum aspeed_lpc_snoop_index index; ++ u32 hicr5_en; ++ u32 snpwadr_mask; ++ u32 snpwadr_shift; ++ u32 hicrb_en; ++}; + -+static int -+aspeed_mctp_filter_eid(struct aspeed_mctp *priv, void __user *userbuf) -+{ -+ struct aspeed_mctp_filter_eid eid; + struct aspeed_lpc_snoop_channel { ++ const struct aspeed_lpc_snoop_channel_cfg *cfg; + bool enabled; + struct kfifo fifo; + wait_queue_head_t wq; +@@ -67,10 +82,28 @@ + struct aspeed_lpc_snoop { + struct regmap *regmap; + int irq; +- struct clk *clk; +- struct aspeed_lpc_snoop_channel chan[NUM_SNOOP_CHANNELS]; ++ struct aspeed_lpc_snoop_channel chan[ASPEED_LPC_SNOOP_INDEX_MAX + 1]; + }; + ++static const struct aspeed_lpc_snoop_channel_cfg channel_cfgs[ASPEED_LPC_SNOOP_INDEX_MAX + 1] = { ++ { ++ .index = ASPEED_LPC_SNOOP_INDEX_0, ++ .hicr5_en = HICR5_EN_SNP0W | HICR5_ENINT_SNP0W, ++ .snpwadr_mask = SNPWADR_CH0_MASK, ++ .snpwadr_shift = SNPWADR_CH0_SHIFT, ++ .hicrb_en = HICRB_ENSNP0D, ++ }, ++ { ++ .index = ASPEED_LPC_SNOOP_INDEX_1, ++ .hicr5_en = HICR5_EN_SNP1W | HICR5_ENINT_SNP1W, ++ .snpwadr_mask = SNPWADR_CH1_MASK, ++ .snpwadr_shift = SNPWADR_CH1_SHIFT, ++ .hicrb_en = HICRB_ENSNP1D, ++ }, ++}; + -+ if (copy_from_user(&eid, userbuf, sizeof(eid))) { -+ dev_err(priv->dev, "copy from user failed\n"); -+ return -EFAULT; -+ } ++static DEFINE_IDA(aspeed_lpc_snoop_ida); + -+ if (eid.enable) { -+ regmap_update_bits(priv->map, ASPEED_MCTP_EID, -+ MCTP_EID, eid.eid); -+ regmap_update_bits(priv->map, ASPEED_MCTP_CTRL, -+ MATCHING_EID, MATCHING_EID); + static struct aspeed_lpc_snoop_channel *snoop_file_to_chan(struct file *file) + { + return container_of(file->private_data, +@@ -136,12 +169,19 @@ + return IRQ_NONE; + + /* Check if one of the snoop channels is interrupting */ +- reg &= (HICR6_STR_SNP0W | HICR6_STR_SNP1W); +- if (!reg) ++ if (!(reg & (HICR6_STR_SNP0W | HICR6_STR_SNP1W))) + return IRQ_NONE; + +- /* Ack pending IRQs */ +- regmap_write(lpc_snoop->regmap, HICR6, reg); ++ /* Check if NFE WA is set */ ++ if (reg & HICR6_NFE_WA) { ++ /* Ack pending IRQs with keeping NFE WA */ ++ regmap_write(lpc_snoop->regmap, HICR6, ++ (HICR6_STR_SNP0W | HICR6_STR_SNP1W | HICR6_NFE_WA)); + } else { -+ regmap_update_bits(priv->map, ASPEED_MCTP_CTRL, -+ MATCHING_EID, 0); ++ /* Ack pending IRQs */ ++ regmap_write(lpc_snoop->regmap, HICR6, ++ (HICR6_STR_SNP0W | HICR6_STR_SNP1W)); + } -+ return 0; -+} -+ -+static int aspeed_mctp_get_bdf(struct aspeed_mctp *priv, void __user *userbuf) -+{ -+ struct aspeed_mctp_get_bdf bdf = { _get_bdf(priv) }; + + /* Read and save most recent snoop'ed data byte to FIFO */ + regmap_read(lpc_snoop->regmap, SNPWDR, &data); +@@ -182,108 +222,92 @@ + return 0; + } + +-static int aspeed_lpc_enable_snoop(struct aspeed_lpc_snoop *lpc_snoop, +- struct device *dev, +- int channel, u16 lpc_port) ++__attribute__((nonnull)) ++static int aspeed_lpc_enable_snoop(struct device *dev, ++ struct aspeed_lpc_snoop *lpc_snoop, ++ struct aspeed_lpc_snoop_channel *channel, ++ const struct aspeed_lpc_snoop_channel_cfg *cfg, ++ u16 lpc_port) + { +- int rc = 0; +- u32 hicr5_en, snpwadr_mask, snpwadr_shift, hicrb_en; +- const struct aspeed_lpc_snoop_model_data *model_data = +- of_device_get_match_data(dev); ++ const struct aspeed_lpc_snoop_model_data *model_data; ++ int rc = 0, id; + +- if (WARN_ON(lpc_snoop->chan[channel].enabled)) ++ if (WARN_ON(channel->enabled)) + return -EBUSY; + +- init_waitqueue_head(&lpc_snoop->chan[channel].wq); +- /* Create FIFO datastructure */ +- rc = kfifo_alloc(&lpc_snoop->chan[channel].fifo, +- SNOOP_FIFO_SIZE, GFP_KERNEL); ++ init_waitqueue_head(&channel->wq); + -+ if (copy_to_user(userbuf, &bdf, sizeof(bdf))) { -+ dev_err(priv->dev, "copy to user failed\n"); -+ return -EFAULT; -+ } -+ return 0; -+} ++ channel->cfg = cfg; ++ channel->miscdev.minor = MISC_DYNAMIC_MINOR; ++ channel->miscdev.fops = &snoop_fops; ++ channel->miscdev.parent = dev; + -+static int -+aspeed_mctp_get_medium_id(struct aspeed_mctp *priv, void __user *userbuf) -+{ -+ struct aspeed_mctp_get_medium_id id = { 0x09 }; /* PCIe revision 2.0 */ ++ id = ida_alloc(&aspeed_lpc_snoop_ida, GFP_KERNEL); ++ if (id < 0) ++ return id; + -+ if (copy_to_user(userbuf, &id, sizeof(id))) { -+ dev_err(priv->dev, "copy to user failed\n"); -+ return -EFAULT; -+ } -+ return 0; -+} ++ channel->miscdev.name = ++ devm_kasprintf(dev, GFP_KERNEL, "%s%d", DEVICE_NAME, id); ++ if (!channel->miscdev.name) ++ return -ENOMEM; + -+static int -+aspeed_mctp_get_mtu(struct aspeed_mctp *priv, void __user *userbuf) -+{ -+ struct aspeed_mctp_get_mtu id = { ASPEED_MCTP_MTU }; ++ rc = kfifo_alloc(&channel->fifo, SNOOP_FIFO_SIZE, GFP_KERNEL); + if (rc) + return rc; + +- lpc_snoop->chan[channel].miscdev.minor = MISC_DYNAMIC_MINOR; +- lpc_snoop->chan[channel].miscdev.name = +- devm_kasprintf(dev, GFP_KERNEL, "%s%d", DEVICE_NAME, channel); +- if (!lpc_snoop->chan[channel].miscdev.name) { +- rc = -ENOMEM; +- goto err_free_fifo; +- } +- lpc_snoop->chan[channel].miscdev.fops = &snoop_fops; +- lpc_snoop->chan[channel].miscdev.parent = dev; +- rc = misc_register(&lpc_snoop->chan[channel].miscdev); ++ rc = misc_register(&channel->miscdev); + if (rc) + goto err_free_fifo; + + /* Enable LPC snoop channel at requested port */ +- switch (channel) { +- case 0: +- hicr5_en = HICR5_EN_SNP0W | HICR5_ENINT_SNP0W; +- snpwadr_mask = SNPWADR_CH0_MASK; +- snpwadr_shift = SNPWADR_CH0_SHIFT; +- hicrb_en = HICRB_ENSNP0D; +- break; +- case 1: +- hicr5_en = HICR5_EN_SNP1W | HICR5_ENINT_SNP1W; +- snpwadr_mask = SNPWADR_CH1_MASK; +- snpwadr_shift = SNPWADR_CH1_SHIFT; +- hicrb_en = HICRB_ENSNP1D; +- break; +- default: +- rc = -EINVAL; +- goto err_misc_deregister; +- } +- +- regmap_update_bits(lpc_snoop->regmap, HICR5, hicr5_en, hicr5_en); +- regmap_update_bits(lpc_snoop->regmap, SNPWADR, snpwadr_mask, +- lpc_port << snpwadr_shift); +- if (model_data->has_hicrb_ensnp) +- regmap_update_bits(lpc_snoop->regmap, HICRB, +- hicrb_en, hicrb_en); ++ regmap_set_bits(lpc_snoop->regmap, HICR5, cfg->hicr5_en); ++ regmap_update_bits(lpc_snoop->regmap, SNPWADR, cfg->snpwadr_mask, ++ lpc_port << cfg->snpwadr_shift); + -+ if (copy_to_user(userbuf, &id, sizeof(id))) { -+ dev_err(priv->dev, "copy to user failed\n"); -+ return -EFAULT; -+ } -+ return 0; ++ model_data = of_device_get_match_data(dev); ++ if (model_data && model_data->has_hicrb_ensnp) ++ regmap_set_bits(lpc_snoop->regmap, HICRB, cfg->hicrb_en); + +- lpc_snoop->chan[channel].enabled = true; ++ channel->enabled = true; + + return 0; + +-err_misc_deregister: +- misc_deregister(&lpc_snoop->chan[channel].miscdev); + err_free_fifo: +- kfifo_free(&lpc_snoop->chan[channel].fifo); ++ kfifo_free(&channel->fifo); + return rc; + } + ++__attribute__((nonnull)) + static void aspeed_lpc_disable_snoop(struct aspeed_lpc_snoop *lpc_snoop, +- int channel) ++ struct aspeed_lpc_snoop_channel *channel) + { +- if (!lpc_snoop->chan[channel].enabled) ++ if (!channel->enabled) + return; + +- switch (channel) { +- case 0: +- regmap_update_bits(lpc_snoop->regmap, HICR5, +- HICR5_EN_SNP0W | HICR5_ENINT_SNP0W, +- 0); +- break; +- case 1: +- regmap_update_bits(lpc_snoop->regmap, HICR5, +- HICR5_EN_SNP1W | HICR5_ENINT_SNP1W, +- 0); +- break; +- default: +- return; +- } ++ /* Disable interrupts along with the device */ ++ regmap_clear_bits(lpc_snoop->regmap, HICR5, channel->cfg->hicr5_en); + +- lpc_snoop->chan[channel].enabled = false; ++ channel->enabled = false; + /* Consider improving safety wrt concurrent reader(s) */ +- misc_deregister(&lpc_snoop->chan[channel].miscdev); +- kfifo_free(&lpc_snoop->chan[channel].fifo); ++ misc_deregister(&channel->miscdev); ++ kfifo_free(&channel->fifo); +} + -+int aspeed_mctp_get_eid_bdf(struct mctp_client *client, u8 eid, u16 *bdf) ++static void aspeed_lpc_snoop_remove(struct platform_device *pdev) +{ -+ struct aspeed_mctp_endpoint *endpoint; -+ int ret = -ENOENT; ++ struct aspeed_lpc_snoop *lpc_snoop = dev_get_drvdata(&pdev->dev); + -+ mutex_lock(&client->priv->endpoints_lock); -+ list_for_each_entry(endpoint, &client->priv->endpoints, link) { -+ if (endpoint->data.eid_info.eid == eid) { -+ *bdf = endpoint->data.eid_info.bdf; -+ ret = 0; -+ break; -+ } -+ } -+ mutex_unlock(&client->priv->endpoints_lock); ++ /* Disable both snoop channels */ ++ aspeed_lpc_disable_snoop(lpc_snoop, &lpc_snoop->chan[0]); ++ aspeed_lpc_disable_snoop(lpc_snoop, &lpc_snoop->chan[1]); + } + + static int aspeed_lpc_snoop_probe(struct platform_device *pdev) + { + struct aspeed_lpc_snoop *lpc_snoop; +- struct device *dev; + struct device_node *np; +- u32 port; ++ struct device *dev; ++ int idx; + int rc; + + dev = &pdev->dev; +@@ -293,77 +317,40 @@ + return -ENOMEM; + + np = pdev->dev.parent->of_node; +- if (!of_device_is_compatible(np, "aspeed,ast2400-lpc-v2") && +- !of_device_is_compatible(np, "aspeed,ast2500-lpc-v2") && +- !of_device_is_compatible(np, "aspeed,ast2600-lpc-v2")) { +- dev_err(dev, "unsupported LPC device binding\n"); +- return -ENODEV; +- } + + lpc_snoop->regmap = syscon_node_to_regmap(np); +- if (IS_ERR(lpc_snoop->regmap)) { +- dev_err(dev, "Couldn't get regmap\n"); +- return -ENODEV; +- } ++ if (IS_ERR(lpc_snoop->regmap)) ++ return dev_err_probe(dev, PTR_ERR(lpc_snoop->regmap), "Couldn't get regmap\n"); + + dev_set_drvdata(&pdev->dev, lpc_snoop); + +- rc = of_property_read_u32_index(dev->of_node, "snoop-ports", 0, &port); +- if (rc) { +- dev_err(dev, "no snoop ports configured\n"); +- return -ENODEV; +- } +- +- lpc_snoop->clk = devm_clk_get(dev, NULL); +- if (IS_ERR(lpc_snoop->clk)) { +- rc = PTR_ERR(lpc_snoop->clk); +- if (rc != -EPROBE_DEFER) +- dev_err(dev, "couldn't get clock\n"); +- return rc; +- } +- rc = clk_prepare_enable(lpc_snoop->clk); +- if (rc) { +- dev_err(dev, "couldn't enable clock\n"); +- return rc; +- } +- + rc = aspeed_lpc_snoop_config_irq(lpc_snoop, pdev); + if (rc) +- goto err; ++ return rc; + +- rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 0, port); +- if (rc) +- goto err; ++ static_assert(ARRAY_SIZE(channel_cfgs) == ARRAY_SIZE(lpc_snoop->chan), ++ "Broken implementation assumption regarding cfg count"); ++ for (idx = ASPEED_LPC_SNOOP_INDEX_0; idx <= ASPEED_LPC_SNOOP_INDEX_MAX; idx++) { ++ u32 port; + -+ return ret; -+} -+EXPORT_SYMBOL_GPL(aspeed_mctp_get_eid_bdf); ++ rc = of_property_read_u32_index(dev->of_node, "snoop-ports", idx, &port); ++ if (rc) ++ break; + +- /* Configuration of 2nd snoop channel port is optional */ +- if (of_property_read_u32_index(dev->of_node, "snoop-ports", +- 1, &port) == 0) { +- rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 1, port); +- if (rc) { +- aspeed_lpc_disable_snoop(lpc_snoop, 0); +- goto err; +- } ++ rc = aspeed_lpc_enable_snoop(dev, lpc_snoop, &lpc_snoop->chan[idx], ++ &channel_cfgs[idx], port); ++ if (rc) ++ goto cleanup_channels; + } + +- return 0; ++ return idx == ASPEED_LPC_SNOOP_INDEX_0 ? -ENODEV : 0; + +-err: +- clk_disable_unprepare(lpc_snoop->clk); ++cleanup_channels: ++ aspeed_lpc_snoop_remove(pdev); + + return rc; + } + +-static void aspeed_lpc_snoop_remove(struct platform_device *pdev) +-{ +- struct aspeed_lpc_snoop *lpc_snoop = dev_get_drvdata(&pdev->dev); +- +- /* Disable both snoop channels */ +- aspeed_lpc_disable_snoop(lpc_snoop, 0); +- aspeed_lpc_disable_snoop(lpc_snoop, 1); +- +- clk_disable_unprepare(lpc_snoop->clk); +-} +- + 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 +@@ -0,0 +1,312 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright Aspeed Technology Inc. (C) 2025. All rights reserved ++ */ + -+int aspeed_mctp_get_eid(struct mctp_client *client, u16 bdf, -+ u8 domain_id, u8 *eid) -+{ -+ struct aspeed_mctp_endpoint *endpoint; -+ int ret = -ENOENT; ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ mutex_lock(&client->priv->endpoints_lock); ++#define __ASPEED_MBOX_IOCTL_MAGIC 'X' ++#define ASPEED_MBOX_IOCTL_CAPS _IOR(__ASPEED_MBOX_IOCTL_MAGIC, 0, uint32_t[4]) ++#define ASPEED_MBOX_IOCTL_SEND _IOW(__ASPEED_MBOX_IOCTL_MAGIC, 1, uint32_t[8]) ++#define ASPEED_MBOX_IOCTL_RECV _IOR(__ASPEED_MBOX_IOCTL_MAGIC, 2, uint32_t[8]) + -+ list_for_each_entry(endpoint, &client->priv->endpoints, link) { -+ if (endpoint->data.eid_ext_info.domain_id == domain_id && -+ endpoint->data.eid_ext_info.bdf == bdf) { -+ *eid = endpoint->data.eid_ext_info.eid; -+ ret = 0; -+ break; -+ } -+ } ++/** ++ * struct aspeed_mem - Description of a ASPEED memory buffer ++ * @buf: Shared memory base address ++ * @size: Shared memory byte size ++ */ ++struct aspeed_mem { ++ void __iomem *buf; ++ phys_addr_t phys_addr; ++ resource_size_t size; ++}; + -+ mutex_unlock(&client->priv->endpoints_lock); -+ return ret; -+} -+EXPORT_SYMBOL_GPL(aspeed_mctp_get_eid); ++/* ++ * Message prototype of IPC. It should be defined per your usage. ++ * cmd: type of message ++ * len: length of message ++ */ ++struct ast_mbox_msg { ++ u32 cmd; ++ u32 len; ++}; + -+static int -+aspeed_mctp_get_eid_info(struct aspeed_mctp *priv, void __user *userbuf, -+ enum mctp_address_type addr_format) -+{ -+ int count = 0; -+ int ret = 0; -+ struct aspeed_mctp_get_eid_info get_eid; -+ struct aspeed_mctp_endpoint *endpoint; -+ void *user_ptr; -+ size_t count_to_copy; ++/* ++ * struct ast_mbox_chan - Description of a ASPEED mailbox channel ++ * @cl: Mailbox client ++ * @mdev: Misc device ++ * @chan: Mailbox channel ++ * @tx_base: Information of tx shmem ++ * @rx_base: Information of rx shmem ++ * @rx_buffer: buffer to store data on callback ++ * @rx_wait: Wait queue for receiving messages ++ * @rx_msg_lock: Spinlock to protect rx_buffer ++ */ ++struct ast_mbox_info { ++ struct device *dev; ++ struct mbox_client cl; ++ struct miscdevice mdev; ++ struct mbox_chan *chan; ++ struct aspeed_mem tx_base; ++ struct aspeed_mem rx_base; ++ char *rx_buffer; ++ wait_queue_head_t rx_wait; ++ spinlock_t rx_msg_lock; /* spinlock to protect rx_buffer */ ++}; + -+ if (copy_from_user(&get_eid, userbuf, sizeof(get_eid))) { -+ dev_err(priv->dev, "copy from user failed\n"); -+ return -EFAULT; -+ } ++static ssize_t mbox_read(struct file *fp, char __user *buf, size_t nbytes, loff_t *off) ++{ ++ struct ast_mbox_info *info = container_of(fp->private_data, struct ast_mbox_info, mdev); ++ int ret; + -+ mutex_lock(&priv->endpoints_lock); ++ if (nbytes == 0) ++ return 0; + -+ if (get_eid.count == 0) { -+ count = priv->endpoints_count; -+ goto out_unlock; ++ if (!info->rx_base.buf) { ++ dev_err(info->dev, "No RX shmem\n"); ++ return -EINVAL; + } + -+ user_ptr = u64_to_user_ptr(get_eid.ptr); -+ count_to_copy = get_eid.count > priv->endpoints_count ? -+ priv->endpoints_count : get_eid.count; -+ list_for_each_entry(endpoint, &priv->endpoints, link) { -+ if (endpoint->data.eid_info.eid < get_eid.start_eid) -+ continue; -+ if (count >= count_to_copy) -+ break; -+ -+ if (addr_format == ASPEED_MCTP_EXTENDED_ADDR_FORMAT) -+ ret = copy_to_user(&(((struct aspeed_mctp_eid_ext_info *) -+ user_ptr)[count]), -+ &endpoint->data, -+ sizeof(struct aspeed_mctp_eid_ext_info)); -+ else -+ ret = copy_to_user(&(((struct aspeed_mctp_eid_info *) -+ user_ptr)[count]), -+ &endpoint->data, -+ sizeof(struct aspeed_mctp_eid_info)); -+ -+ if (ret) { -+ dev_err(priv->dev, "copy to user failed\n"); -+ ret = -EFAULT; -+ goto out_unlock; -+ } -+ count++; ++ if (nbytes > info->rx_base.size) { ++ dev_warn(info->dev, "Read size %zu exceeds RX shmem size %llu\n", ++ nbytes, info->rx_base.size); ++ nbytes = info->rx_base.size; + } + -+out_unlock: -+ get_eid.count = count; -+ if (copy_to_user(userbuf, &get_eid, sizeof(get_eid))) { -+ dev_err(priv->dev, "copy to user failed\n"); -+ ret = -EFAULT; -+ } ++ ret = copy_to_user((void __user *)buf, info->rx_base.buf, nbytes); ++ if (ret) ++ return -EFAULT; + -+ mutex_unlock(&priv->endpoints_lock); -+ return ret; ++ return nbytes; +} + -+static int -+eid_info_cmp(void *priv, const struct list_head *a, const struct list_head *b) ++static ssize_t mbox_write(struct file *fp, const char *buf, size_t nbytes, loff_t *off) +{ -+ struct aspeed_mctp_endpoint *endpoint_a; -+ struct aspeed_mctp_endpoint *endpoint_b; ++ struct ast_mbox_info *info = container_of(fp->private_data, struct ast_mbox_info, mdev); ++ int ret; + -+ if (a == b) ++ if (nbytes == 0) + return 0; + -+ endpoint_a = list_entry(a, typeof(*endpoint_a), link); -+ endpoint_b = list_entry(b, typeof(*endpoint_b), link); -+ -+ if (endpoint_a->data.eid_info.eid < endpoint_b->data.eid_info.eid) -+ return -1; -+ else if (endpoint_a->data.eid_info.eid > endpoint_b->data.eid_info.eid) -+ return 1; ++ if (!info->tx_base.buf) { ++ dev_err(info->dev, "No TX shmem\n"); ++ return -EINVAL; ++ } + -+ return 0; -+} ++ if (nbytes > info->tx_base.size) { ++ dev_warn(info->dev, "Write size %zu exceeds TX shmem size %llu\n", ++ nbytes, info->tx_base.size); ++ nbytes = info->tx_base.size; ++ } + -+static void aspeed_mctp_eid_info_list_remove(struct list_head *list) -+{ -+ struct aspeed_mctp_endpoint *endpoint; -+ struct aspeed_mctp_endpoint *tmp; ++ ret = copy_from_user(info->tx_base.buf, (void __user *)buf, nbytes); ++ if (ret) ++ return -EFAULT; + -+ list_for_each_entry_safe(endpoint, tmp, list, link) { -+ list_del(&endpoint->link); -+ kfree(endpoint); -+ } ++ return nbytes; +} + -+static bool -+aspeed_mctp_eid_info_list_valid(struct list_head *list) ++static __poll_t mbox_poll(struct file *fp, struct poll_table_struct *wait) +{ -+ struct aspeed_mctp_endpoint *endpoint; -+ struct aspeed_mctp_endpoint *next; ++ struct ast_mbox_info *info = container_of(fp->private_data, struct ast_mbox_info, mdev); ++ __poll_t mask = 0; + -+ list_for_each_entry(endpoint, list, link) { -+ next = list_next_entry(endpoint, link); -+ if (&next->link == list) -+ break; ++ poll_wait(fp, &info->rx_wait, wait); + -+ /* duplicted eids */ -+ if (next->data.eid_info.eid == endpoint->data.eid_info.eid) -+ return false; -+ } ++ if (info->rx_buffer) ++ mask |= POLLIN | POLLRDNORM; + -+ return true; ++ return mask; +} + -+static int -+aspeed_mctp_set_eid_info(struct aspeed_mctp *priv, void __user *userbuf, -+ enum mctp_address_type addr_format) ++static long mbox_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ -+ struct list_head list = LIST_HEAD_INIT(list); -+ struct aspeed_mctp_set_eid_info set_eid; -+ void *user_ptr; -+ struct aspeed_mctp_endpoint *endpoint; ++ struct ast_mbox_info *info = container_of(fp->private_data, struct ast_mbox_info, mdev); ++ u32 *data; ++ u32 msg[8]; ++ unsigned long flags; + int ret = 0; -+ u8 eid = 0; -+ size_t i; -+ -+ if (copy_from_user(&set_eid, userbuf, sizeof(set_eid))) { -+ dev_err(priv->dev, "copy from user failed\n"); -+ return -EFAULT; -+ } -+ -+ if (set_eid.count > ASPEED_MCTP_EID_INFO_MAX) -+ return -EINVAL; -+ -+ user_ptr = u64_to_user_ptr(set_eid.ptr); -+ for (i = 0; i < set_eid.count; i++) { -+ endpoint = kzalloc(sizeof(*endpoint), GFP_KERNEL); -+ if (!endpoint) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ memset(endpoint, 0, sizeof(*endpoint)); -+ -+ if (addr_format == ASPEED_MCTP_EXTENDED_ADDR_FORMAT) -+ ret = copy_from_user(&endpoint->data, -+ &(((struct aspeed_mctp_eid_ext_info *) -+ user_ptr)[i]), -+ sizeof(struct aspeed_mctp_eid_ext_info)); -+ else -+ ret = copy_from_user(&endpoint->data, -+ &(((struct aspeed_mctp_eid_info *) -+ user_ptr)[i]), -+ sizeof(struct aspeed_mctp_eid_info)); + ++ switch (cmd) { ++ case ASPEED_MBOX_IOCTL_CAPS: ++ data = (u32 *)arg; ++ data[0] = (info->tx_base.phys_addr) >> 8; ++ data[1] = info->tx_base.size; ++ data[2] = (info->rx_base.phys_addr) >> 8; ++ data[3] = info->rx_base.size; ++ break; ++ case ASPEED_MBOX_IOCTL_SEND: ++ ret = copy_from_user(msg, (void __user *)arg, sizeof(msg)); + if (ret) { -+ dev_err(priv->dev, "copy from user failed\n"); -+ kfree(endpoint); -+ ret = -EFAULT; -+ goto out; ++ dev_dbg(info->dev, "Failed to copy message from user\n"); ++ return -EFAULT; + } + -+ /* Detect self EID */ -+ if (_get_bdf(priv) == endpoint->data.eid_info.bdf) { -+ /* -+ * XXX Use smallest EID with matching BDF. -+ * On some platforms there could be multiple endpoints -+ * with same BDF in routing table. -+ */ -+ if (eid == 0 || endpoint->data.eid_info.eid < eid) -+ eid = endpoint->data.eid_info.eid; ++ ret = mbox_send_message(info->chan, msg); ++ if (ret < 0) ++ dev_dbg(info->dev, "Failed to send message via mailbox\n"); ++ break; ++ case ASPEED_MBOX_IOCTL_RECV: ++ spin_lock_irqsave(&info->rx_msg_lock, flags); ++ if (!info->rx_buffer) { ++ spin_unlock_irqrestore(&info->rx_msg_lock, flags); ++ dev_dbg(info->dev, "No message received\n"); ++ return -EAGAIN; + } -+ -+ list_add_tail(&endpoint->link, &list); -+ } -+ -+ list_sort(NULL, &list, eid_info_cmp); -+ if (!aspeed_mctp_eid_info_list_valid(&list)) { ++ ret = copy_to_user((void __user *)arg, info->rx_buffer, sizeof(msg)); ++ info->rx_buffer = NULL; ++ spin_unlock_irqrestore(&info->rx_msg_lock, flags); ++ if (ret) { ++ dev_dbg(info->dev, "Failed to copy message to user\n"); ++ return -EFAULT; ++ } ++ break; ++ default: ++ dev_err(info->dev, "Unsupported cmd: %x\n", cmd); + ret = -EINVAL; -+ goto out; + } + -+ mutex_lock(&priv->endpoints_lock); -+ if (list_empty(&priv->endpoints)) -+ list_splice_init(&list, &priv->endpoints); -+ else -+ list_swap(&list, &priv->endpoints); -+ priv->endpoints_count = set_eid.count; -+ priv->eid = eid; -+ mutex_unlock(&priv->endpoints_lock); -+out: -+ aspeed_mctp_eid_info_list_remove(&list); + return ret; +} + -+static int aspeed_mctp_set_own_eid(struct aspeed_mctp *priv, void __user *userbuf) -+{ -+ struct aspeed_mctp_set_own_eid data; ++static const struct file_operations aspeed_mbox_fops = { ++ .owner = THIS_MODULE, ++ .read = mbox_read, ++ .write = mbox_write, ++ .poll = mbox_poll, ++ .unlocked_ioctl = mbox_ioctl, ++}; + -+ if (copy_from_user(&data, userbuf, sizeof(data))) { -+ dev_err(priv->dev, "copy from user failed\n"); -+ return -EFAULT; -+ } ++static void mbox_rx_callback(struct mbox_client *client, void *message) ++{ ++ struct ast_mbox_info *info = container_of(client, struct ast_mbox_info, cl); ++ unsigned long flags; + -+ priv->eid = data.eid; ++ spin_lock_irqsave(&info->rx_msg_lock, flags); ++ info->rx_buffer = message; ++ spin_unlock_irqrestore(&info->rx_msg_lock, flags); + -+ return 0; ++ wake_up_interruptible(&info->rx_wait); +} + -+static long -+aspeed_mctp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++static int aspeed_mbox_probe(struct platform_device *pdev) +{ -+ struct mctp_client *client = file->private_data; -+ struct aspeed_mctp *priv = client->priv; -+ void __user *userbuf = (void __user *)arg; ++ struct ast_mbox_info *info; ++ struct resource *res; ++ struct device *dev = &pdev->dev; + int ret; ++ u32 tx_tout = -1; + -+ switch (cmd) { -+ case ASPEED_MCTP_IOCTL_FILTER_EID: -+ ret = aspeed_mctp_filter_eid(priv, userbuf); -+ break; -+ -+ case ASPEED_MCTP_IOCTL_GET_BDF: -+ ret = aspeed_mctp_get_bdf(priv, userbuf); -+ break; -+ -+ case ASPEED_MCTP_IOCTL_GET_MEDIUM_ID: -+ ret = aspeed_mctp_get_medium_id(priv, userbuf); -+ break; -+ -+ case ASPEED_MCTP_IOCTL_GET_MTU: -+ ret = aspeed_mctp_get_mtu(priv, userbuf); -+ break; -+ -+ case ASPEED_MCTP_IOCTL_REGISTER_DEFAULT_HANDLER: -+ ret = aspeed_mctp_register_default_handler(client); -+ break; ++ info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return -ENOMEM; + -+ case ASPEED_MCTP_IOCTL_REGISTER_TYPE_HANDLER: -+ ret = aspeed_mctp_register_type_handler(client, userbuf); -+ break; ++ info->tx_base.buf = devm_platform_get_and_ioremap_resource(pdev, 0, &res); ++ if (PTR_ERR(info->tx_base.buf) == -EBUSY) { ++ /* if reserved area in SRAM, try just ioremap */ ++ info->tx_base.size = resource_size(res); ++ info->tx_base.buf = devm_ioremap(dev, res->start, info->tx_base.size); ++ } ++ if (IS_ERR(info->tx_base.buf)) { ++ info->tx_base.buf = NULL; ++ } else { ++ info->tx_base.phys_addr = res->start; ++ info->tx_base.size = resource_size(res); ++ } + -+ case ASPEED_MCTP_IOCTL_UNREGISTER_TYPE_HANDLER: -+ ret = aspeed_mctp_unregister_type_handler(client, userbuf); -+ break; ++ info->rx_base.buf = devm_platform_get_and_ioremap_resource(pdev, 1, &res); ++ if (PTR_ERR(info->rx_base.buf) == -EBUSY) { ++ /* if reserved area in SRAM, try just ioremap */ ++ info->rx_base.size = resource_size(res); ++ info->rx_base.buf = devm_ioremap(dev, res->start, info->rx_base.size); ++ } ++ if (IS_ERR(info->rx_base.buf)) { ++ info->rx_base = info->tx_base; ++ } else { ++ info->rx_base.phys_addr = res->start; ++ info->rx_base.size = resource_size(res); ++ } + -+ case ASPEED_MCTP_IOCTL_GET_EID_INFO: -+ ret = aspeed_mctp_get_eid_info(priv, userbuf, ASPEED_MCTP_GENERIC_ADDR_FORMAT); -+ break; ++ if (device_property_read_u32(dev, "aspeed,tx-timeout", &tx_tout)) ++ tx_tout = -1; + -+ case ASPEED_MCTP_IOCTL_GET_EID_EXT_INFO: -+ ret = aspeed_mctp_get_eid_info(priv, userbuf, ASPEED_MCTP_EXTENDED_ADDR_FORMAT); -+ break; ++ dev_info(dev, "TX shmem: phys 0x%pa size %llu\n", ++ &info->tx_base.phys_addr, info->tx_base.size); ++ dev_info(dev, "RX shmem: phys 0x%pa size %llu\n", ++ &info->rx_base.phys_addr, info->rx_base.size); ++ dev_info(dev, "TX timeout: %u ms\n", tx_tout); + -+ case ASPEED_MCTP_IOCTL_SET_EID_INFO: -+ ret = aspeed_mctp_set_eid_info(priv, userbuf, ASPEED_MCTP_GENERIC_ADDR_FORMAT); -+ break; ++ info->cl.dev = dev; ++ info->cl.rx_callback = mbox_rx_callback; ++ info->cl.tx_block = true; ++ info->cl.knows_txdone = false; ++ info->cl.tx_tout = tx_tout; + -+ case ASPEED_MCTP_IOCTL_SET_EID_EXT_INFO: -+ ret = aspeed_mctp_set_eid_info(priv, userbuf, ASPEED_MCTP_EXTENDED_ADDR_FORMAT); -+ break; ++ info->chan = mbox_request_channel(&info->cl, 0); ++ if (IS_ERR(info->chan)) { ++ dev_err(dev, "failed to request channel err %ld\n", ++ PTR_ERR(info->chan)); ++ return -EPROBE_DEFER; ++ } + -+ case ASPEED_MCTP_IOCTL_SET_OWN_EID: -+ ret = aspeed_mctp_set_own_eid(priv, userbuf); -+ break; ++ info->rx_buffer = NULL; ++ init_waitqueue_head(&info->rx_wait); ++ spin_lock_init(&info->rx_msg_lock); ++ info->dev = dev; ++ platform_set_drvdata(pdev, info); + -+ default: -+ dev_err(priv->dev, "Command not found\n"); -+ ret = -ENOTTY; ++ info->mdev.parent = dev; ++ info->mdev.minor = MISC_DYNAMIC_MINOR; ++ info->mdev.name = dev_name(dev); ++ info->mdev.fops = &aspeed_mbox_fops; ++ ret = misc_register(&info->mdev); ++ if (ret) { ++ dev_err(dev, "failed to register misc device\n"); ++ return ret; + } + -+ return ret; ++ return 0; +} + -+static __poll_t aspeed_mctp_poll(struct file *file, -+ struct poll_table_struct *pt) ++static void aspeed_mbox_remove(struct platform_device *pdev) +{ -+ struct mctp_client *client = file->private_data; -+ __poll_t ret = 0; -+ struct aspeed_mctp *priv = client->priv; -+ struct mctp_channel *rx = &priv->rx; -+ u32 mctp_ctrl; -+ u32 mctp_int_sts; -+ -+ if (priv->miss_mctp_int) { -+ regmap_read(priv->map, ASPEED_MCTP_CTRL, &mctp_ctrl); -+ if (!(mctp_ctrl & RX_CMD_READY)) -+ rx->stopped = true; -+ /* Polling the RX_CMD_RECEIVE_INT to ensure rx_tasklet can find the data */ -+ regmap_read(priv->map, ASPEED_MCTP_INT_STS, &mctp_int_sts); -+ if (mctp_int_sts & RX_CMD_RECEIVE_INT) -+ regmap_write(priv->map, ASPEED_MCTP_INT_STS, -+ mctp_int_sts); -+ } -+ -+ tasklet_hi_schedule(&priv->rx.tasklet); -+ poll_wait(file, &client->wait_queue, pt); ++ struct ast_mbox_info *info = platform_get_drvdata(pdev); + -+ if (!ptr_ring_full_bh(&client->tx_queue)) -+ ret |= EPOLLOUT; ++ mbox_free_channel(info->chan); ++ misc_deregister(&info->mdev); ++} + -+ if (__ptr_ring_peek(&client->rx_queue)) -+ ret |= EPOLLIN; ++static const struct of_device_id mbox_cl_match[] = { ++ { .compatible = "aspeed,aspeed-mbox" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mbox_test_match); + -+ return ret; -+} ++static struct platform_driver aspeed_mbox_driver = { ++ .driver = { ++ .name = "aspeed_mbox_client", ++ .of_match_table = mbox_cl_match, ++ }, ++ .probe = aspeed_mbox_probe, ++ .remove = aspeed_mbox_remove, ++}; ++module_platform_driver(aspeed_mbox_driver); + -+#ifdef CONFIG_MCTP_TRANSPORT_PCIE_VDM -+static int aspeed_mctp_pcie_vdm_op_send_pkt(struct device *dev, -+ u8 *data, size_t size) -+{ -+ struct mctp_pcie_packet *packet; -+ struct platform_device *pdev; -+ struct aspeed_mctp *priv; -+ int rc; ++MODULE_AUTHOR("Jammy Huang "); ++MODULE_DESCRIPTION("ASPEED MBOX CLIENT driver"); ++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 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2020, Intel Corporation. + -+ pdev = to_platform_device(dev); -+ priv = platform_get_drvdata(pdev); -+ // freed at aspeed-mctp tx tasklet or send failure -+ packet = aspeed_mctp_packet_alloc(GFP_KERNEL); ++#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 + -+ if (!packet) { -+ dev_err(priv->dev, "failed to alloc packet\n"); -+ return -ENOMEM; -+ } ++#include + -+ memcpy((u8 *)&packet->data.hdr, data, PCIE_VDM_HDR_SIZE); -+ memcpy((u8 *)&packet->data.payload, data + PCIE_VDM_HDR_SIZE, size); -+ packet->size = (size + PCIE_VDM_HDR_SIZE); ++/* AST2600 MCTP Controller registers */ ++#define ASPEED_MCTP_CTRL 0x000 ++#define TX_CMD_TRIGGER BIT(0) ++#define RX_CMD_READY BIT(4) ++#define MATCHING_EID BIT(9) + -+ rc = aspeed_mctp_send_packet(priv->default_client, packet); -+ if (rc) { -+ dev_err(priv->dev, "failed to send packet\n"); -+ aspeed_mctp_packet_free(packet); -+ return rc; -+ } -+ return 0; -+} ++#define ASPEED_MCTP_TX_CMD 0x004 ++#define ASPEED_MCTP_RX_CMD 0x008 + -+static u8 *aspeed_mctp_pcie_vdm_op_recv_pkt(struct device *dev) -+{ -+ struct platform_device *pdev; -+ struct aspeed_mctp *priv; -+ struct mctp_pcie_packet *rx_packet; ++#define ASPEED_MCTP_INT_STS 0x00c ++#define ASPEED_MCTP_INT_EN 0x010 ++#define TX_CMD_SENT_INT BIT(0) ++#define TX_CMD_LAST_INT BIT(1) ++#define TX_CMD_WRONG_INT BIT(2) ++#define RX_CMD_RECEIVE_INT BIT(8) ++#define RX_CMD_NO_MORE_INT BIT(9) + -+ pdev = to_platform_device(dev); -+ priv = platform_get_drvdata(pdev); -+ rx_packet = aspeed_mctp_receive_packet(priv->default_client, 0); ++#define ASPEED_MCTP_EID 0x014 ++#define MEMORY_SPACE_MAPPING GENMASK(31, 28) ++#define MCTP_EID GENMASK(7, 0) ++#define ASPEED_MCTP_OBFF_CTRL 0x018 + -+ if (IS_ERR(rx_packet)) { -+ if (PTR_ERR(rx_packet) == -ETIME) { -+ dev_dbg(priv->dev, "no packet received\n"); -+ } else { -+ dev_err(priv->dev, "failed to receive packet: %ld\n", -+ PTR_ERR(rx_packet)); -+ } -+ return (u8 *)rx_packet; -+ } -+ return (u8 *)&rx_packet->data; -+} ++#define ASPEED_MCTP_ENGINE_CTRL 0x01c ++#define TX_MAX_PAYLOAD_SIZE_SHIFT 0 ++#define TX_MAX_PAYLOAD_SIZE_MASK GENMASK(1, TX_MAX_PAYLOAD_SIZE_SHIFT) ++#define TX_MAX_PAYLOAD_SIZE(x) \ ++ (((x) << TX_MAX_PAYLOAD_SIZE_SHIFT) & TX_MAX_PAYLOAD_SIZE_MASK) ++#define RX_MAX_PAYLOAD_SIZE_SHIFT 4 ++#define RX_MAX_PAYLOAD_SIZE_MASK GENMASK(5, RX_MAX_PAYLOAD_SIZE_SHIFT) ++#define RX_MAX_PAYLOAD_SIZE(x) \ ++ (((x) << RX_MAX_PAYLOAD_SIZE_SHIFT) & RX_MAX_PAYLOAD_SIZE_MASK) ++#define FIFO_LAYOUT_SHIFT 8 ++#define FIFO_LAYOUT_MASK GENMASK(9, FIFO_LAYOUT_SHIFT) ++#define FIFO_LAYOUT(x) \ ++ (((x) << FIFO_LAYOUT_SHIFT) & FIFO_LAYOUT_MASK) + -+static void aspeed_mctp_pcie_vdm_op_uninit(struct device *dev) -+{ -+ struct platform_device *pdev; -+ struct aspeed_mctp *priv; ++#define ASPEED_MCTP_RX_BUF_ADDR 0x08 ++#define ASPEED_MCTP_RX_BUF_HI_ADDR 0x020 ++#define ASPEED_MCTP_RX_BUF_SIZE 0x024 ++#define ASPEED_MCTP_RX_BUF_RD_PTR 0x028 ++#define UPDATE_RX_RD_PTR BIT(31) ++#define RX_BUF_RD_PTR_MASK GENMASK(11, 0) ++#define ASPEED_MCTP_RX_BUF_WR_PTR 0x02c ++#define RX_BUF_WR_PTR_MASK GENMASK(11, 0) + -+ pdev = to_platform_device(dev); -+ priv = platform_get_drvdata(pdev); ++#define ASPEED_MCTP_TX_BUF_ADDR 0x04 ++#define ASPEED_MCTP_TX_BUF_HI_ADDR 0x030 ++#define ASPEED_MCTP_TX_BUF_SIZE 0x034 ++#define ASPEED_MCTP_TX_BUF_RD_PTR 0x038 ++#define UPDATE_TX_RD_PTR BIT(31) ++#define TX_BUF_RD_PTR_MASK GENMASK(11, 0) ++#define ASPEED_MCTP_TX_BUF_WR_PTR 0x03c ++#define TX_BUF_WR_PTR_MASK GENMASK(11, 0) ++#define ASPEED_G7_MCTP_PCIE_BDF 0x04c + -+ aspeed_mctp_flush_all_tx_queues(priv); -+ aspeed_mctp_flush_rx_queue(priv->default_client); -+ aspeed_mctp_delete_client(priv->default_client); -+} ++#define ADDR_LEN GENMASK(26, 0) ++#define DATA_ADDR(x) (((x) >> 4) & ADDR_LEN) + -+static const struct mctp_pcie_vdm_ops aspeed_mctp_pcie_vdm_ops = { -+ .send_packet = aspeed_mctp_pcie_vdm_op_send_pkt, -+ .recv_packet = aspeed_mctp_pcie_vdm_op_recv_pkt, -+ .free_packet = aspeed_mctp_packet_free, -+ .uninit = aspeed_mctp_pcie_vdm_op_uninit, -+}; ++/* TX command */ ++#define TX_LAST_CMD BIT(31) ++#define TX_DATA_ADDR_SHIFT 4 ++#define TX_DATA_ADDR_MASK GENMASK(30, TX_DATA_ADDR_SHIFT) ++#define TX_DATA_ADDR(x) \ ++ ((DATA_ADDR(x) << TX_DATA_ADDR_SHIFT) & TX_DATA_ADDR_MASK) ++#define TX_RESERVED_1_MASK GENMASK(1, 0) /* must be 1 */ ++#define TX_RESERVED_1 1 ++#define TX_STOP_AFTER_CMD BIT(16) ++#define TX_INTERRUPT_AFTER_CMD BIT(15) ++#define TX_PACKET_SIZE_SHIFT 2 ++#define TX_PACKET_SIZE_MASK GENMASK(12, TX_PACKET_SIZE_SHIFT) ++#define TX_PACKET_SIZE(x) \ ++ (((x) << TX_PACKET_SIZE_SHIFT) & TX_PACKET_SIZE_MASK) ++#define TX_RESERVED_0_MASK GENMASK(1, 0) /* MBZ */ ++#define TX_RESERVED_0 0 + -+#endif ++/* RX command */ ++#define RX_INTERRUPT_AFTER_CMD BIT(2) ++#define RX_DATA_ADDR_SHIFT 4 ++#define RX_DATA_ADDR_MASK GENMASK(30, RX_DATA_ADDR_SHIFT) ++#define RX_DATA_ADDR(x) \ ++ ((DATA_ADDR(x) << RX_DATA_ADDR_SHIFT) & RX_DATA_ADDR_MASK) + -+static const struct file_operations aspeed_mctp_fops = { -+ .owner = THIS_MODULE, -+ .open = aspeed_mctp_open, -+ .release = aspeed_mctp_release, -+ .read = aspeed_mctp_read, -+ .write = aspeed_mctp_write, -+ .unlocked_ioctl = aspeed_mctp_ioctl, -+ .poll = aspeed_mctp_poll, -+}; ++#define ADDR_LEN_2500 GENMASK(23, 0) ++#define DATA_ADDR_2500(x) (((x) >> 7) & ADDR_LEN_2500) + -+static const struct regmap_config aspeed_mctp_regmap_cfg = { -+ .reg_bits = 32, -+ .reg_stride = 4, -+ .val_bits = 32, -+ .max_register = ASPEED_G7_MCTP_PCIE_BDF, -+}; ++/* TX command for ast2500 */ ++#define TX_DATA_ADDR_MASK_2500 GENMASK(30, 8) ++#define TX_DATA_ADDR_2500(x) \ ++ FIELD_PREP(TX_DATA_ADDR_MASK_2500, DATA_ADDR_2500(x)) ++#define TX_PACKET_SIZE_2500(x) \ ++ FIELD_PREP(GENMASK(11, 2), x) ++#define TX_PACKET_DEST_EID GENMASK(7, 0) ++#define TX_PACKET_TARGET_ID GENMASK(31, 16) ++#define TX_PACKET_ROUTING_TYPE BIT(14) ++#define TX_PACKET_TAG_OWNER BIT(13) ++#define TX_PACKET_PADDING_LEN GENMASK(1, 0) + -+struct device_type aspeed_mctp_type = { -+ .name = "aspeed-mctp", -+}; ++/* Rx command for ast2500 */ ++#define RX_LAST_CMD BIT(31) ++#define RX_DATA_ADDR_MASK_2500 GENMASK(29, 7) ++#define RX_DATA_ADDR_2500(x) \ ++ FIELD_PREP(RX_DATA_ADDR_MASK_2500, DATA_ADDR_2500(x)) ++#define RX_PACKET_SIZE GENMASK(30, 24) ++#define RX_PACKET_SRC_EID GENMASK(23, 16) ++#define RX_PACKET_ROUTING_TYPE GENMASK(15, 14) ++#define RX_PACKET_TAG_OWNER BIT(13) ++#define RX_PACKET_SEQ_NUMBER GENMASK(12, 11) ++#define RX_PACKET_MSG_TAG GENMASK(10, 8) ++#define RX_PACKET_SOM BIT(7) ++#define RX_PACKET_EOM BIT(6) ++#define RX_PACKET_PADDING_LEN GENMASK(5, 4) + -+static void aspeed_mctp_send_pcie_uevent(struct kobject *kobj, bool ready) -+{ -+ char buf[32]; -+ char *envp[2]; ++/* HW buffer sizes */ ++#define TX_PACKET_COUNT 48 ++#define RX_PACKET_COUNT 96 ++#if (RX_PACKET_COUNT % 4 != 0) ++#error The Rx buffer size should be 4-aligned. ++#error 1.Make runaway wrap boundary can be determined in Ast2600 A1/A2. ++#error 2.Fix the runaway read pointer bug in Ast2600 A3. ++#endif ++#define TX_MAX_PACKET_COUNT (TX_BUF_RD_PTR_MASK + 1) ++#define RX_MAX_PACKET_COUNT (RX_BUF_RD_PTR_MASK + 1) + -+ snprintf(buf, sizeof(buf), ASPEED_MCTP_READY "=%d", ready ? 1 : 0); -+ envp[0] = buf; -+ envp[1] = NULL; ++/* Per client packet cache sizes */ ++#define RX_RING_COUNT 64 ++#define TX_RING_COUNT 64 + -+ kobject_uevent_env(kobj, KOBJ_CHANGE, envp); -+} ++/* PCIe Host Controller registers */ ++#define ASPEED_PCIE_LINK 0x0c0 ++#define PCIE_LINK_STS BIT(5) ++#define ASPEED_PCIE_MISC_STS_1 0x0c4 + -+static void aspeed_mctp_irq_enable(struct aspeed_mctp *priv) -+{ -+ u32 enable = TX_CMD_SENT_INT | TX_CMD_WRONG_INT | -+ RX_CMD_RECEIVE_INT | RX_CMD_NO_MORE_INT; ++/* PCIe Host Controller registers */ ++#define ASPEED_G7_PCIE_LOCATE 0x300 ++#define PCIE_LOCATE_IO BIT(0) ++#define ASPEED_G7_PCIE_LINK 0x358 ++#define PCIE_G7_LINK_STS BIT(8) ++#define ASPEED_G7_IO_PCIE_LINK 0x344 ++#define PCIE_G7_IO_LINK_STS BIT(18) + -+ regmap_write(priv->map, ASPEED_MCTP_INT_EN, enable); -+} ++/* PCI address definitions */ ++#define PCI_DEV_NUM_MASK GENMASK(4, 0) ++#define PCI_BUS_NUM_SHIFT 5 ++#define PCI_BUS_NUM_MASK GENMASK(12, PCI_BUS_NUM_SHIFT) ++#define GET_PCI_DEV_NUM(x) ((x) & PCI_DEV_NUM_MASK) ++#define GET_PCI_BUS_NUM(x) (((x) & PCI_BUS_NUM_MASK) >> PCI_BUS_NUM_SHIFT) + -+static void aspeed_mctp_irq_disable(struct aspeed_mctp *priv) -+{ -+ regmap_write(priv->map, ASPEED_MCTP_INT_EN, 0); -+} ++/* MCTP header definitions */ ++#define MCTP_HDR_SRC_EID_OFFSET 14 ++#define MCTP_HDR_TAG_OFFSET 15 ++#define MCTP_HDR_SOM BIT(7) ++#define MCTP_HDR_EOM BIT(6) ++#define MCTP_HDR_SOM_EOM (MCTP_HDR_SOM | MCTP_HDR_EOM) ++#define MCTP_PAYLOAD_TYPE_OFFSET 0 ++#define MCTP_HDR_TYPE_CONTROL 0 ++#define MCTP_HDR_TYPE_VDM_PCI 0x7e ++#define MCTP_HDR_TYPE_SPDM 0x5 ++#define MCTP_HDR_TYPE_BASE_LAST MCTP_HDR_TYPE_SPDM ++#define MCTP_PAYLOAD_VENDOR_OFFSET 1 ++#define MCTP_PAYLOAD_VDM_TYPE_OFFSET 3 + -+static void aspeed_mctp_pcie_setup(struct aspeed_mctp *priv) -+{ -+ int ret; -+ u8 tx_max_payload_size; -+ u8 rx_max_payload_size; -+ struct kobject *kobj = &priv->mctp_miscdev.this_device->kobj; ++/* MCTP header DW little endian mask definitions */ ++/* 0th DW */ ++#define MCTP_HDR_DW_LE_ROUTING_TYPE GENMASK(26, 24) ++#define MCTP_HDR_DW_LE_PACKET_SIZE GENMASK(9, 0) ++/* 1st DW */ ++#define MCTP_HDR_DW_LE_PADDING_LEN GENMASK(13, 12) ++/* 2nd DW */ ++#define MCTP_HDR_DW_LE_TARGET_ID GENMASK(31, 16) ++/* 3rd DW */ ++#define MCTP_HDR_DW_LE_TAG_OWNER BIT(3) ++#define MCTP_HDR_DW_LE_DEST_EID GENMASK(23, 16) + -+ ret = _get_bdf(priv); ++#define ASPEED_MCTP_2600 0 ++#define ASPEED_MCTP_2600A3 1 + -+ if (ret >= 0) { -+ cancel_delayed_work(&priv->pcie.rst_dwork); -+ if (priv->match_data->need_address_mapping) -+ regmap_update_bits(priv->map, ASPEED_MCTP_EID, -+ MEMORY_SPACE_MAPPING, BIT(31)); ++#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 + -+ /* Only set TX MPS since HW will parse RX packet to decide how many bytes to receive -+ * based on the length field in PCIe VDM header. -+ */ -+ if (priv->match_data->dma_need_64bits_width) { -+ tx_max_payload_size = -+ FIELD_GET(TX_MAX_PAYLOAD_SIZE_MASK, -+ ilog2(ASPEED_MCTP_MTU >> 6)); -+ } else { -+ /* -+ * In ast2600, tx som and eom will not match expected result. -+ * e.g. When Maximum Transmit Unit (MTU) set to 64 byte, and then transfer -+ * size set between 61 ~ 124 (MTU-3 ~ 2*MTU-4), the engine will set all -+ * packet vdm header eom to 1, no matter what it setted. To fix that -+ * issue, the driver set MTU to next level(e.g. 64 to 128). -+ */ -+ tx_max_payload_size = -+ FIELD_GET(TX_MAX_PAYLOAD_SIZE_MASK, -+ fls(ASPEED_MCTP_MTU >> 6)); -+ } ++#define ASPEED_G7_SCU_PCIE0_CTRL_OFFSET 0xa60 ++#define ASPEED_G7_SCU_PCIE1_CTRL_OFFSET 0xae0 ++#define ASPEED_G7_SCU_PCIE_CTRL_VDM_EN BIT(1) + -+ regmap_update_bits(priv->map, ASPEED_MCTP_ENGINE_CTRL, -+ TX_MAX_PAYLOAD_SIZE_MASK | RX_MAX_PAYLOAD_SIZE_MASK, -+ (rx_max_payload_size << RX_MAX_PAYLOAD_SIZE_SHIFT) | tx_max_payload_size); ++struct aspeed_mctp_match_data { ++ u32 rx_cmd_size; ++ u32 tx_cmd_size; ++ u32 packet_unit_size; ++ bool need_address_mapping; ++ bool vdm_hdr_direct_xfer; ++ bool fifo_auto_surround; ++ bool dma_need_64bits_width; ++ u32 scu_pcie_ctrl_offset; ++}; + -+ aspeed_mctp_flush_all_tx_queues(priv); -+ if (!priv->miss_mctp_int) { -+ aspeed_mctp_irq_enable(priv); -+ } else { -+ if (priv->rx_det_period_us) -+ schedule_delayed_work(&priv->rx_det_dwork, -+ usecs_to_jiffies(priv->rx_det_period_us)); -+ } -+ aspeed_mctp_rx_trigger(&priv->rx); -+ aspeed_mctp_send_pcie_uevent(kobj, true); -+ } else { -+ schedule_delayed_work(&priv->pcie.rst_dwork, -+ msecs_to_jiffies(1000)); -+ } -+} ++struct aspeed_mctp_rx_cmd { ++ u32 rx_lo; ++ u32 rx_hi; ++}; + -+static void aspeed_mctp_reset_work(struct work_struct *work) -+{ -+ struct aspeed_mctp *priv = container_of(work, typeof(*priv), -+ pcie.rst_dwork.work); -+ struct kobject *kobj = &priv->mctp_miscdev.this_device->kobj; ++struct aspeed_mctp_tx_cmd { ++ u32 tx_lo; ++ u32 tx_hi; ++}; + -+ if (priv->pcie.need_uevent) { -+ aspeed_mctp_send_pcie_uevent(kobj, false); -+ priv->pcie.need_uevent = false; -+ } ++struct aspeed_g7_mctp_tx_cmd { ++ u32 tx_lo; ++ u32 tx_mid; ++ u32 tx_hi; ++ u32 reserved; ++}; + -+ aspeed_mctp_pcie_setup(priv); -+} ++struct mctp_buffer { ++ void *vaddr; ++ dma_addr_t dma_handle; ++}; + -+static void aspeed_mctp_rx_detect_work(struct work_struct *work) -+{ -+ struct aspeed_mctp *priv = -+ container_of(work, typeof(*priv), rx_det_dwork.work); ++struct mctp_channel { ++ struct mctp_buffer data; ++ struct mctp_buffer cmd; ++ struct tasklet_struct tasklet; ++ u32 buffer_count; ++ u32 rd_ptr; ++ u32 wr_ptr; ++ bool stopped; ++}; + -+ tasklet_hi_schedule(&priv->rx.tasklet); -+ schedule_delayed_work(&priv->rx_det_dwork, -+ usecs_to_jiffies(priv->rx_det_period_us)); -+} ++struct aspeed_mctp { ++ struct device *dev; ++ struct miscdevice mctp_miscdev; ++ const struct aspeed_mctp_match_data *match_data; ++ struct regmap *map; ++ struct reset_control *reset; ++ /* ++ * The reset of the dma block in the MCTP-RC is connected to ++ * another reset pin. ++ */ ++ struct reset_control *reset_dma; ++ struct mctp_channel tx; ++ struct mctp_channel rx; ++ struct list_head clients; ++ struct mctp_client *default_client; ++ struct list_head mctp_type_handlers; ++ /* ++ * clients_lock protects list of clients, list of type handlers ++ * and default client ++ */ ++ spinlock_t clients_lock; ++ struct list_head endpoints; ++ size_t endpoints_count; ++ /* ++ * endpoints_lock protects list of endpoints ++ */ ++ struct mutex endpoints_lock; ++ struct { ++ struct regmap *map; ++ struct delayed_work rst_dwork; ++ bool need_uevent; ++ } pcie; ++ struct { ++ bool enable; ++ bool first_loop; ++ int packet_counter; ++ } rx_runaway_wa; ++ bool rx_warmup; ++ u8 eid; ++ struct platform_device *peci_mctp; ++ /* Use the flag to identify RC or EP */ ++ bool rc_f; ++ /* Use the flag to identify the support of MCTP interrupt */ ++ bool miss_mctp_int; ++ /* Rx hardware buffer size */ ++ u32 rx_packet_count; ++ /* Rx pointer ring size */ ++ u32 rx_ring_count; ++ /* Tx pointer ring size */ ++ u32 tx_ring_count; ++ /* 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 ++ struct net_device *ndev; ++#endif ++}; + -+static void aspeed_mctp_channels_init(struct aspeed_mctp *priv) -+{ -+ aspeed_mctp_rx_chan_init(&priv->rx); -+ aspeed_mctp_tx_chan_init(&priv->tx); -+} ++struct mctp_client { ++ struct kref ref; ++ struct aspeed_mctp *priv; ++ struct ptr_ring tx_queue; ++ struct ptr_ring rx_queue; ++ struct list_head link; ++ wait_queue_head_t wait_queue; ++}; + -+static irqreturn_t aspeed_mctp_irq_handler(int irq, void *arg) -+{ -+ struct aspeed_mctp *priv = arg; -+ u32 handled = 0; -+ u32 status; ++struct mctp_type_handler { ++ u8 mctp_type; ++ u16 pci_vendor_id; ++ u16 vdm_type; ++ u16 vdm_mask; ++ struct mctp_client *client; ++ struct list_head link; ++}; + -+ regmap_read(priv->map, ASPEED_MCTP_INT_STS, &status); -+ regmap_write(priv->map, ASPEED_MCTP_INT_STS, status); ++union aspeed_mctp_eid_data_info { ++ struct aspeed_mctp_eid_info eid_info; ++ struct aspeed_mctp_eid_ext_info eid_ext_info; ++}; + -+ if (status & TX_CMD_SENT_INT) { -+ tasklet_hi_schedule(&priv->tx.tasklet); -+ if (!priv->match_data->fifo_auto_surround) -+ priv->tx.rd_ptr = (priv->tx.rd_ptr + 1) % TX_PACKET_COUNT; -+ handled |= TX_CMD_SENT_INT; -+ } ++enum mctp_address_type { ++ ASPEED_MCTP_GENERIC_ADDR_FORMAT = 0, ++ ASPEED_MCTP_EXTENDED_ADDR_FORMAT = 1 ++}; + -+ if (status & TX_CMD_WRONG_INT) { -+ /* TODO: print the actual command */ -+ dev_warn(priv->dev, "TX wrong"); ++struct aspeed_mctp_endpoint { ++ union aspeed_mctp_eid_data_info data; ++ struct list_head link; ++}; + -+ handled |= TX_CMD_WRONG_INT; -+ } ++struct kmem_cache *packet_cache; + -+ if (status & RX_CMD_RECEIVE_INT) { -+ tasklet_hi_schedule(&priv->rx.tasklet); ++static void data_dump(struct aspeed_mctp *priv, struct mctp_pcie_packet_data *data) ++{ ++ int i; + -+ handled |= RX_CMD_RECEIVE_INT; ++ dev_dbg(priv->dev, "Address %zu", (size_t)data); ++ dev_dbg(priv->dev, "VDM header:"); ++ for (i = 0; i < PCIE_VDM_HDR_SIZE_DW; i++) { ++ dev_dbg(priv->dev, "%02x %02x %02x %02x", data->hdr[i] & 0xff, ++ (data->hdr[i] >> 8) & 0xff, (data->hdr[i] >> 16) & 0xff, ++ (data->hdr[i] >> 24) & 0xff); + } -+ -+ if (status & RX_CMD_NO_MORE_INT) { -+ dev_dbg(priv->dev, "RX full"); -+ priv->rx.stopped = true; -+ tasklet_hi_schedule(&priv->rx.tasklet); -+ -+ handled |= RX_CMD_NO_MORE_INT; ++ dev_dbg(priv->dev, "Data payload:"); ++ for (i = 0; i < PCIE_VDM_DATA_SIZE_DW; i++) { ++ dev_dbg(priv->dev, "%02x %02x %02x %02x", ++ data->payload[i] & 0xff, (data->payload[i] >> 8) & 0xff, ++ (data->payload[i] >> 16) & 0xff, ++ (data->payload[i] >> 24) & 0xff); + } -+ -+ if (!handled) -+ return IRQ_NONE; -+ -+ return IRQ_HANDLED; +} + -+static irqreturn_t aspeed_mctp_pcie_rst_irq_handler(int irq, void *arg) ++void *aspeed_mctp_packet_alloc(gfp_t flags) +{ -+ struct aspeed_mctp *priv = arg; -+ -+ aspeed_mctp_channels_init(priv); -+ -+ priv->pcie.need_uevent = true; -+ priv->eid = 0; -+ -+ schedule_delayed_work(&priv->pcie.rst_dwork, 0); -+ -+ return IRQ_HANDLED; ++ return kmem_cache_alloc(packet_cache, flags); +} ++EXPORT_SYMBOL_GPL(aspeed_mctp_packet_alloc); + -+static void aspeed_mctp_drv_init(struct aspeed_mctp *priv) ++void aspeed_mctp_packet_free(void *packet) +{ -+ INIT_LIST_HEAD(&priv->clients); -+ INIT_LIST_HEAD(&priv->mctp_type_handlers); -+ INIT_LIST_HEAD(&priv->endpoints); ++ kmem_cache_free(packet_cache, packet); ++} ++EXPORT_SYMBOL_GPL(aspeed_mctp_packet_free); + -+ spin_lock_init(&priv->clients_lock); -+ mutex_init(&priv->endpoints_lock); ++static int _get_bdf(struct aspeed_mctp *priv) ++{ ++ u32 reg; ++ u16 bdf, devfn; + -+ INIT_DELAYED_WORK(&priv->pcie.rst_dwork, aspeed_mctp_reset_work); ++ if (priv->match_data->dma_need_64bits_width) { ++ regmap_read(priv->pcie.map, ASPEED_G7_PCIE_LOCATE, ®); ++ if (!(reg & PCIE_LOCATE_IO)) { ++ regmap_read(priv->pcie.map, ASPEED_G7_PCIE_LINK, ®); ++ if (!(reg & PCIE_G7_LINK_STS)) ++ return -ENETDOWN; ++ regmap_read(priv->map, ASPEED_G7_MCTP_PCIE_BDF, ®); ++ bdf = PCI_DEVID(PCI_BUS_NUM(reg), reg & 0xff); ++ } else { ++ regmap_read(priv->pcie.map, ASPEED_G7_IO_PCIE_LINK, ++ ®); ++ if (!(reg & PCIE_G7_IO_LINK_STS)) ++ return -ENETDOWN; ++ regmap_read(priv->map, ASPEED_G7_MCTP_PCIE_BDF, ®); ++ bdf = PCI_DEVID(PCI_BUS_NUM(reg), reg & 0xff); ++ } ++ } else { ++ regmap_read(priv->pcie.map, ASPEED_PCIE_LINK, ®); ++ if (!(reg & PCIE_LINK_STS)) ++ return -ENETDOWN; ++ regmap_read(priv->pcie.map, ASPEED_PCIE_MISC_STS_1, ®); + -+ tasklet_init(&priv->tx.tasklet, aspeed_mctp_tx_tasklet, -+ (unsigned long)&priv->tx); -+ tasklet_init(&priv->rx.tasklet, aspeed_mctp_rx_tasklet, -+ (unsigned long)&priv->rx); ++ reg = reg & (PCI_BUS_NUM_MASK | PCI_DEV_NUM_MASK); ++ /* only support function 0 */ ++ devfn = GET_PCI_DEV_NUM(reg) << 3; ++ bdf = PCI_DEVID(GET_PCI_BUS_NUM(reg), devfn); ++ } ++ ++ return bdf; +} + -+static void aspeed_mctp_drv_fini(struct aspeed_mctp *priv) ++static uint32_t chip_version(struct device *dev) +{ -+ aspeed_mctp_eid_info_list_remove(&priv->endpoints); -+ tasklet_disable(&priv->tx.tasklet); -+ tasklet_kill(&priv->tx.tasklet); -+ tasklet_disable(&priv->rx.tasklet); -+ tasklet_kill(&priv->rx.tasklet); ++ struct regmap *scu; ++ u32 revid0, revid1; + -+ cancel_delayed_work_sync(&priv->pcie.rst_dwork); -+ if (priv->miss_mctp_int) -+ cancel_delayed_work_sync(&priv->rx_det_dwork); ++ 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); ++ if (revid0 == ID0_AST2600A3 && revid1 == ID1_AST2600A3) { ++ /* AST2600-A3 */ ++ return ASPEED_MCTP_2600A3; ++ } else if (revid0 == ID0_AST2620A3 && revid1 == ID1_AST2620A3) { ++ /* AST2620-A3 */ ++ return ASPEED_MCTP_2600A3; ++ } else if (revid0 == ID0_AST2605A3 && revid1 == ID1_AST2605A3) { ++ /* AST2605-A3 */ ++ return ASPEED_MCTP_2600A3; ++ } else if (revid0 == ID0_AST2625A3 && revid1 == ID1_AST2625A3) { ++ /* AST2605-A3 */ ++ return ASPEED_MCTP_2600A3; ++ } ++ return ASPEED_MCTP_2600; +} + -+static int aspeed_mctp_resources_init(struct aspeed_mctp *priv) ++static int pcie_vdm_enable(struct device *dev) +{ -+ struct platform_device *pdev = to_platform_device(priv->dev); -+ void __iomem *regs; ++ int ret = 0; ++ struct regmap *scu; ++ const struct aspeed_mctp_match_data *match_data = ++ of_device_get_match_data(dev); + -+ regs = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(regs)) { -+ dev_err(priv->dev, "Failed to get regmap!\n"); -+ return PTR_ERR(regs); ++ 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); + } ++ ret = regmap_update_bits(scu, match_data->scu_pcie_ctrl_offset, ++ ASPEED_G7_SCU_PCIE_CTRL_VDM_EN, ++ ASPEED_G7_SCU_PCIE_CTRL_VDM_EN); ++ return ret; ++} + -+ priv->map = devm_regmap_init_mmio(priv->dev, regs, -+ &aspeed_mctp_regmap_cfg); -+ if (IS_ERR(priv->map)) -+ return PTR_ERR(priv->map); ++/* ++ * HW produces and expects VDM header in little endian and payload in network order. ++ * To allow userspace to use network order for the whole packet, PCIe VDM header needs ++ * to be swapped. ++ */ ++static void aspeed_mctp_swap_pcie_vdm_hdr(struct mctp_pcie_packet_data *data) ++{ ++ int i; + -+ priv->reset = -+ priv->rc_f ? -+ devm_reset_control_get_by_index(priv->dev, 0) : -+ devm_reset_control_get_shared_by_index(priv->dev, 0); -+ if (IS_ERR(priv->reset)) { -+ dev_err(priv->dev, "Failed to get reset!\n"); -+ return PTR_ERR(priv->reset); -+ } ++ for (i = 0; i < PCIE_VDM_HDR_SIZE_DW; i++) ++ data->hdr[i] = swab32(data->hdr[i]); ++} + -+ 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); ++static void aspeed_mctp_rx_trigger(struct mctp_channel *rx) ++{ ++ struct aspeed_mctp *priv = container_of(rx, typeof(*priv), rx); ++ u32 reg; ++ ++ /* ++ * Even though rx_buf_addr doesn't change, if we don't do the write ++ * here, the HW doesn't trigger RX. We're also clearing the ++ * RX_CMD_READY bit, otherwise we're observing a rare case where ++ * trigger isn't registered by the HW, and we're ending up with stuck ++ * HW (not reacting to wr_ptr writes). ++ * Also, note that we're writing 0 as wr_ptr. If we're writing other ++ * value, the HW behaves in a bizarre way that's hard to explain... ++ */ ++ regmap_update_bits(priv->map, ASPEED_MCTP_CTRL, RX_CMD_READY, 0); ++ if (priv->match_data->fifo_auto_surround) { ++ regmap_write(priv->map, ASPEED_MCTP_RX_BUF_ADDR, ++ rx->cmd.dma_handle); ++ if (priv->match_data->dma_need_64bits_width) ++ regmap_write(priv->map, ASPEED_MCTP_RX_BUF_HI_ADDR, ++ upper_32_bits(rx->cmd.dma_handle)); ++ } else { ++ regmap_read(priv->map, ASPEED_MCTP_RX_BUF_ADDR, ®); ++ if (!reg) { ++ regmap_write(priv->map, ASPEED_MCTP_RX_BUF_ADDR, ++ rx->cmd.dma_handle); ++ } else if (reg == (rx->cmd.dma_handle & GENMASK(28, 3))) { ++ dev_info(priv->dev, ++ "Already initialized - skipping rx dma set\n"); ++ } else { ++ dev_err(priv->dev, ++ "The memory of rx dma can't be changed after the controller is activated\n"); ++ return; + } + } -+ priv->pcie.map = -+ syscon_regmap_lookup_by_phandle(priv->dev->of_node, -+ "aspeed,pcieh"); -+ if (IS_ERR(priv->pcie.map)) { -+ dev_err(priv->dev, "Failed to find PCIe Host regmap!\n"); -+ return PTR_ERR(priv->pcie.map); -+ } ++ regmap_write(priv->map, ASPEED_MCTP_RX_BUF_WR_PTR, 0); + -+ platform_set_drvdata(pdev, priv); ++ /* After re-enabling RX we need to restart WA logic */ ++ if (priv->rx_runaway_wa.enable) ++ priv->rx.buffer_count = priv->rx_packet_count; ++ /* ++ * When Rx warmup MCTP controller may store first packet into the 0th to the ++ * 3rd cmd. In ast2600 A3, If the packet isn't stored in the 0th cmd we need ++ * to change the rx buffer size to avoid rx runaway in first loop. In ast2600 ++ * A1/A2, after first loop hardware is guaranteed to use (RX_PACKET_COUNT - 4) ++ * buffers. ++ */ ++ priv->rx_warmup = true; ++ priv->rx_runaway_wa.first_loop = true; ++ priv->rx_runaway_wa.packet_counter = 0; + -+ return 0; ++ regmap_update_bits(priv->map, ASPEED_MCTP_CTRL, RX_CMD_READY, ++ RX_CMD_READY); +} + -+static void aspeed_release_rmem(void *d) ++static void aspeed_mctp_tx_trigger(struct mctp_channel *tx, bool notify) +{ -+ of_reserved_mem_device_release(d); -+} ++ struct aspeed_mctp *priv = container_of(tx, typeof(*priv), tx); ++ u32 ctrl_val; ++ int ret; + -+static int aspeed_mctp_dma_init(struct aspeed_mctp *priv) -+{ -+ struct mctp_channel *tx = &priv->tx; -+ struct mctp_channel *rx = &priv->rx; -+ size_t alloc_size; -+ int ret = -ENOMEM; ++ if (notify) { ++ if (priv->match_data->dma_need_64bits_width) { ++ struct aspeed_g7_mctp_tx_cmd *last_cmd; + -+ BUILD_BUG_ON(TX_PACKET_COUNT >= TX_MAX_PACKET_COUNT); -+ BUILD_BUG_ON(RX_PACKET_COUNT >= RX_MAX_PACKET_COUNT); ++ last_cmd = (struct aspeed_g7_mctp_tx_cmd *)tx->cmd.vaddr + ++ (tx->wr_ptr - 1) % TX_PACKET_COUNT; ++ last_cmd->tx_lo |= TX_INTERRUPT_AFTER_CMD; ++ } else { ++ struct aspeed_mctp_tx_cmd *last_cmd; + -+ 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; ++ last_cmd = (struct aspeed_mctp_tx_cmd *)tx->cmd.vaddr + ++ (tx->wr_ptr - 1) % TX_PACKET_COUNT; ++ last_cmd->tx_lo |= TX_INTERRUPT_AFTER_CMD; ++ } + } -+ -+ ret = of_reserved_mem_device_init(priv->dev); ++ if (priv->match_data->fifo_auto_surround) ++ regmap_write(priv->map, ASPEED_MCTP_TX_BUF_WR_PTR, tx->wr_ptr); ++ regmap_update_bits(priv->map, ASPEED_MCTP_CTRL, TX_CMD_TRIGGER, ++ TX_CMD_TRIGGER); ++ ret = regmap_read_poll_timeout_atomic(priv->map, ASPEED_MCTP_CTRL, ++ ctrl_val, ++ !(ctrl_val & TX_CMD_TRIGGER), 0, ++ 1000000); + if (ret) { -+ dev_err(priv->dev, "device does not have specific DMA pool: %d\n", -+ ret); -+ return ret; -+ } ++ u32 rd_ptr, wr_ptr; + -+ ret = devm_add_action_or_reset(priv->dev, aspeed_release_rmem, -+ priv->dev); -+ if (ret) -+ return ret; ++ regmap_write(priv->map, ASPEED_MCTP_TX_BUF_RD_PTR, UPDATE_RX_RD_PTR); ++ regmap_read(priv->map, ASPEED_MCTP_TX_BUF_RD_PTR, &rd_ptr); ++ rd_ptr &= RX_BUF_RD_PTR_MASK; ++ regmap_read(priv->map, ASPEED_MCTP_TX_BUF_WR_PTR, &wr_ptr); ++ wr_ptr &= TX_BUF_RD_PTR_MASK; ++ dev_warn(priv->dev, ++ "Wait tx completed timeout rd_ptr = %x, wr_ptr = %x\n", ++ rd_ptr, wr_ptr); ++ regmap_update_bits(priv->map, ASPEED_MCTP_CTRL, TX_CMD_TRIGGER, ++ 0); ++ } ++} + -+ 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); ++static void aspeed_mctp_tx_cmd_prep(u32 *tx_hdr, struct aspeed_mctp_tx_cmd *tx_cmd) ++{ ++ u32 packet_size, target_id; ++ u8 dest_eid, padding_len, routing_type, tag_owner; + -+ if (!rx->data.vaddr) -+ return -ENOMEM; ++ packet_size = FIELD_GET(MCTP_HDR_DW_LE_PACKET_SIZE, tx_hdr[0]); ++ routing_type = FIELD_GET(MCTP_HDR_DW_LE_ROUTING_TYPE, tx_hdr[0]); ++ routing_type = routing_type ? routing_type - 1 : 0; ++ padding_len = FIELD_GET(MCTP_HDR_DW_LE_PADDING_LEN, tx_hdr[1]); ++ target_id = FIELD_GET(MCTP_HDR_DW_LE_TARGET_ID, tx_hdr[2]); ++ tag_owner = FIELD_GET(MCTP_HDR_DW_LE_TAG_OWNER, tx_hdr[3]); ++ dest_eid = FIELD_GET(MCTP_HDR_DW_LE_DEST_EID, tx_hdr[3]); + -+ alloc_size = PAGE_ALIGN(priv->rx_packet_count * priv->match_data->rx_cmd_size); -+ rx->cmd.vaddr = dma_alloc_coherent(priv->dev, alloc_size, &rx->cmd.dma_handle, GFP_KERNEL); ++ tx_cmd->tx_hi = FIELD_PREP(TX_PACKET_DEST_EID, dest_eid); ++ tx_cmd->tx_lo = FIELD_PREP(TX_PACKET_TARGET_ID, target_id) | ++ TX_INTERRUPT_AFTER_CMD | ++ FIELD_PREP(TX_PACKET_ROUTING_TYPE, routing_type) | ++ FIELD_PREP(TX_PACKET_TAG_OWNER, tag_owner) | ++ TX_PACKET_SIZE_2500(packet_size) | ++ FIELD_PREP(TX_PACKET_PADDING_LEN, padding_len); ++} + -+ if (!rx->cmd.vaddr) -+ goto out_rx_cmd; ++static void aspeed_mctp_emit_tx_cmd(struct mctp_channel *tx, ++ struct mctp_pcie_packet *packet) ++{ ++ struct aspeed_mctp *priv = container_of(tx, typeof(*priv), tx); ++ struct aspeed_mctp_tx_cmd *tx_cmd = ++ (struct aspeed_mctp_tx_cmd *)tx->cmd.vaddr + tx->wr_ptr; ++ struct aspeed_g7_mctp_tx_cmd *tx_cmd_g7 = ++ (struct aspeed_g7_mctp_tx_cmd *)tx->cmd.vaddr + tx->wr_ptr; ++ u32 packet_sz_dw = packet->size / sizeof(u32) - ++ sizeof(packet->data.hdr) / sizeof(u32); ++ u32 offset; + -+ alloc_size = PAGE_ALIGN(TX_PACKET_COUNT * priv->match_data->packet_unit_size); -+ tx->data.vaddr = -+ dma_alloc_coherent(priv->dev, alloc_size, &tx->data.dma_handle, GFP_KERNEL); ++ data_dump(priv, &packet->data); ++ aspeed_mctp_swap_pcie_vdm_hdr(&packet->data); + -+ if (!tx->data.vaddr) -+ goto out_tx_data; -+ alloc_size = PAGE_ALIGN(TX_PACKET_COUNT * priv->match_data->tx_cmd_size); -+ tx->cmd.vaddr = dma_alloc_coherent(priv->dev, alloc_size, &tx->cmd.dma_handle, GFP_KERNEL); ++ if (priv->match_data->vdm_hdr_direct_xfer) { ++ offset = tx->wr_ptr * sizeof(packet->data); ++ memcpy((u8 *)tx->data.vaddr + offset, &packet->data, ++ sizeof(packet->data)); ++ if (priv->match_data->dma_need_64bits_width) { ++ tx_cmd_g7->tx_lo = TX_PACKET_SIZE(packet_sz_dw); ++ tx_cmd_g7->tx_mid = TX_RESERVED_1; ++ tx_cmd_g7->tx_mid |= ((tx->data.dma_handle + offset) & ++ GENMASK(31, 4)); ++ tx_cmd_g7->tx_hi = upper_32_bits((tx->data.dma_handle + offset)); ++ } else { ++ tx_cmd->tx_lo = TX_PACKET_SIZE(packet_sz_dw); ++ tx_cmd->tx_hi = TX_RESERVED_1; ++ tx_cmd->tx_hi |= TX_DATA_ADDR(tx->data.dma_handle + offset); ++ } ++ } else { ++ offset = tx->wr_ptr * sizeof(struct mctp_pcie_packet_data_2500); ++ memcpy((u8 *)tx->data.vaddr + offset, packet->data.payload, ++ sizeof(packet->data.payload)); ++ aspeed_mctp_tx_cmd_prep(packet->data.hdr, tx_cmd); ++ tx_cmd->tx_hi |= TX_DATA_ADDR_2500(tx->data.dma_handle + offset); ++ if (tx->wr_ptr == TX_PACKET_COUNT - 1) ++ tx_cmd->tx_hi |= TX_LAST_CMD; ++ } ++ dev_dbg(priv->dev, "tx->wr_prt: %d, tx_cmd: hi:%08x lo:%08x\n", ++ tx->wr_ptr, tx_cmd->tx_hi, tx_cmd->tx_lo); + -+ if (!tx->cmd.vaddr) -+ goto out_tx_cmd; ++ tx->wr_ptr = (tx->wr_ptr + 1) % TX_PACKET_COUNT; ++} + -+ return 0; -+out_tx_cmd: -+ alloc_size = PAGE_ALIGN(TX_PACKET_COUNT * -+ priv->match_data->packet_unit_size); -+ dma_free_coherent(priv->dev, alloc_size, tx->data.vaddr, -+ tx->data.dma_handle); ++static struct mctp_client *aspeed_mctp_client_alloc(struct aspeed_mctp *priv) ++{ ++ struct mctp_client *client; + -+out_tx_data: -+ alloc_size = PAGE_ALIGN(priv->rx_packet_count * -+ priv->match_data->rx_cmd_size); -+ dma_free_coherent(priv->dev, alloc_size, rx->cmd.vaddr, -+ rx->cmd.dma_handle); ++ client = kzalloc(sizeof(*client), GFP_KERNEL); ++ if (!client) ++ goto out; + -+out_rx_cmd: -+ alloc_size = PAGE_ALIGN(priv->rx_packet_count * -+ priv->match_data->packet_unit_size); -+ dma_free_coherent(priv->dev, alloc_size, rx->data.vaddr, -+ rx->data.dma_handle); ++ kref_init(&client->ref); ++ client->priv = priv; ++ ptr_ring_init(&client->tx_queue, priv->tx_ring_count, GFP_KERNEL); ++ ptr_ring_init(&client->rx_queue, priv->rx_ring_count, GFP_ATOMIC); + -+ return -ENOMEM; ++out: ++ return client; +} + -+static void aspeed_mctp_dma_fini(struct aspeed_mctp *priv) ++static void aspeed_mctp_client_free(struct kref *ref) +{ -+ struct mctp_channel *tx = &priv->tx; -+ struct mctp_channel *rx = &priv->rx; -+ size_t free_size; -+ -+ free_size = PAGE_ALIGN(TX_PACKET_COUNT * priv->match_data->tx_cmd_size); -+ dma_free_coherent(priv->dev, free_size, tx->cmd.vaddr, -+ tx->cmd.dma_handle); -+ -+ free_size = PAGE_ALIGN(priv->rx_packet_count * -+ priv->match_data->rx_cmd_size); -+ dma_free_coherent(priv->dev, free_size, rx->cmd.vaddr, -+ rx->cmd.dma_handle); ++ struct mctp_client *client = container_of(ref, typeof(*client), ref); + -+ free_size = PAGE_ALIGN(TX_PACKET_COUNT * -+ priv->match_data->packet_unit_size); -+ dma_free_coherent(priv->dev, free_size, tx->data.vaddr, -+ tx->data.dma_handle); ++ ptr_ring_cleanup(&client->rx_queue, &aspeed_mctp_packet_free); ++ ptr_ring_cleanup(&client->tx_queue, &aspeed_mctp_packet_free); + -+ free_size = PAGE_ALIGN(priv->rx_packet_count * -+ priv->match_data->packet_unit_size); -+ dma_free_coherent(priv->dev, free_size, rx->data.vaddr, -+ rx->data.dma_handle); ++ kfree(client); +} + -+static int aspeed_mctp_irq_init(struct aspeed_mctp *priv) ++static void aspeed_mctp_client_get(struct mctp_client *client) +{ -+ struct platform_device *pdev = to_platform_device(priv->dev); -+ int irq, ret; -+ -+ irq = platform_get_irq_byname_optional(pdev, "mctp"); -+ if (irq < 0) { -+ /* mctp irq is option */ -+ priv->miss_mctp_int = 1; -+ INIT_DELAYED_WORK(&priv->rx_det_dwork, aspeed_mctp_rx_detect_work); -+ } else { -+ ret = devm_request_irq(priv->dev, irq, aspeed_mctp_irq_handler, -+ IRQF_SHARED, dev_name(&pdev->dev), priv); -+ if (ret) -+ return ret; -+ aspeed_mctp_irq_enable(priv); -+ } -+ irq = platform_get_irq_byname(pdev, "pcie"); -+ if (irq < 0) -+ return irq; ++ lockdep_assert_held(&client->priv->clients_lock); + -+ ret = devm_request_irq(priv->dev, irq, aspeed_mctp_pcie_rst_irq_handler, -+ IRQF_SHARED, dev_name(&pdev->dev), priv); -+ if (ret) -+ return ret; ++ kref_get(&client->ref); ++} + -+ return 0; ++static void aspeed_mctp_client_put(struct mctp_client *client) ++{ ++ kref_put(&client->ref, &aspeed_mctp_client_free); +} + -+static int aspeed_mctp_hw_reset(struct aspeed_mctp *priv) ++static struct mctp_client * ++aspeed_mctp_find_handler(struct aspeed_mctp *priv, ++ struct mctp_pcie_packet *packet) +{ -+ int ret = 0; ++ struct mctp_type_handler *handler; ++ u8 *payload = (u8 *)packet->data.payload; ++ struct mctp_client *client = NULL; ++ u8 mctp_type; ++ u16 vendor = 0; ++ u16 vdm_type = 0; + -+ ret = reset_control_deassert(priv->reset); -+ if (ret) { -+ dev_warn(priv->dev, "Failed to deassert reset\n"); -+ return ret; ++ lockdep_assert_held(&priv->clients_lock); ++ ++ mctp_type = payload[MCTP_PAYLOAD_TYPE_OFFSET]; ++ if (mctp_type == MCTP_HDR_TYPE_VDM_PCI) { ++ vendor = *((u16 *)&payload[MCTP_PAYLOAD_VENDOR_OFFSET]); ++ vdm_type = *((u16 *)&payload[MCTP_PAYLOAD_VDM_TYPE_OFFSET]); + } + -+ if (priv->rc_f) { -+ ret = reset_control_deassert(priv->reset_dma); -+ if (ret) { -+ dev_warn(priv->dev, "Failed to deassert ep reset\n"); -+ return ret; ++ list_for_each_entry(handler, &priv->mctp_type_handlers, link) { ++ if (handler->mctp_type == mctp_type && ++ handler->pci_vendor_id == vendor && ++ handler->vdm_type == (vdm_type & handler->vdm_mask)) { ++ dev_dbg(priv->dev, "Found client for type %x vdm %x\n", ++ mctp_type, handler->vdm_type); ++ client = handler->client; ++ break; + } + } -+ -+ if (priv->match_data->dma_need_64bits_width) -+ ret = pcie_vdm_enable(priv->dev); -+ -+ return ret; ++ return client; +} + -+static int aspeed_mctp_probe(struct platform_device *pdev) ++static void aspeed_mctp_dispatch_packet(struct aspeed_mctp *priv, ++ struct mctp_pcie_packet *packet) +{ -+ struct aspeed_mctp *priv; -+ int ret, id; -+ const char *name; -+ -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ priv->dev = &pdev->dev; -+ priv->rc_f = -+ of_find_property(priv->dev->of_node, "pcie_rc", NULL) ? 1 : 0; -+ priv->match_data = of_device_get_match_data(priv->dev); ++ struct mctp_client *client; ++ int ret; + -+ ret = device_property_read_u32(priv->dev, "aspeed,rx-packet-count", -+ &priv->rx_packet_count); -+ if (ret) { -+ priv->rx_packet_count = RX_PACKET_COUNT; -+ } else if (priv->rx_packet_count % 4 || -+ priv->rx_packet_count >= RX_MAX_PACKET_COUNT) { -+ dev_err(priv->dev, -+ "The aspeed,rx-packet-count:%d should be 4-aligned and less than %ld", -+ priv->rx_packet_count, RX_MAX_PACKET_COUNT); -+ ret = -EINVAL; -+ goto out; -+ } ++ spin_lock(&priv->clients_lock); + -+ ret = device_property_read_u32(priv->dev, "aspeed,rx-ring-count", -+ &priv->rx_ring_count); -+ if (ret) -+ priv->rx_ring_count = RX_RING_COUNT; ++ client = aspeed_mctp_find_handler(priv, packet); + -+ ret = device_property_read_u32(priv->dev, "aspeed,tx-ring-count", -+ &priv->tx_ring_count); -+ if (ret) -+ priv->tx_ring_count = TX_RING_COUNT; ++ if (!client) ++ client = priv->default_client; + -+ ret = device_property_read_u32(priv->dev, "aspeed,rx-det-period-us", -+ &priv->rx_det_period_us); -+ if (ret) -+ priv->rx_det_period_us = 1000; ++ if (client) ++ aspeed_mctp_client_get(client); + -+ aspeed_mctp_drv_init(priv); ++ spin_unlock(&priv->clients_lock); + -+ ret = aspeed_mctp_resources_init(priv); -+ if (ret) { -+ dev_err(priv->dev, "Failed to init resources\n"); -+ goto out_drv; ++ if (client) { ++ ret = ptr_ring_produce(&client->rx_queue, packet); ++ if (ret) { ++ /* ++ * This can happen if client process does not ++ * consume packets fast enough ++ */ ++ dev_dbg(priv->dev, "Failed to store packet in client RX queue\n"); ++ aspeed_mctp_packet_free(packet); ++ } else { ++ wake_up_all(&client->wait_queue); ++ } ++#ifdef CONFIG_MCTP_TRANSPORT_PCIE_VDM ++ mctp_pcie_vdm_receive_packet(priv->ndev); ++#endif ++ aspeed_mctp_client_put(client); ++ } else { ++ dev_dbg(priv->dev, "Failed to dispatch RX packet\n"); ++ aspeed_mctp_packet_free(packet); + } ++} + -+#ifdef CONFIG_MCTP_TRANSPORT_PCIE_VDM -+ struct net_device *ndev; ++static void aspeed_mctp_tx_tasklet(unsigned long data) ++{ ++ struct mctp_channel *tx = (struct mctp_channel *)data; ++ struct aspeed_mctp *priv = container_of(tx, typeof(*priv), tx); + struct mctp_client *client; ++ bool trigger = false; ++ bool full = false; ++ u32 rd_ptr; + -+ /** 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"); -+ goto out_drv; ++ if (priv->match_data->fifo_auto_surround) { ++ regmap_write(priv->map, ASPEED_MCTP_TX_BUF_RD_PTR, UPDATE_RX_RD_PTR); ++ regmap_read(priv->map, ASPEED_MCTP_TX_BUF_RD_PTR, &rd_ptr); ++ rd_ptr &= TX_BUF_RD_PTR_MASK; ++ } else { ++ rd_ptr = tx->rd_ptr; + } + -+ ret = aspeed_mctp_hw_reset(priv); -+ if (ret) -+ goto out_drv; ++ spin_lock(&priv->clients_lock); + -+ aspeed_mctp_channels_init(priv); ++ list_for_each_entry(client, &priv->clients, link) { ++ while (!(full = (tx->wr_ptr + 1) % TX_PACKET_COUNT == rd_ptr)) { ++ struct mctp_pcie_packet *packet; + -+ 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; ++ packet = ptr_ring_consume(&client->tx_queue); ++ if (!packet) ++ break; + -+ ret = aspeed_mctp_irq_init(priv); -+ if (ret) { -+ dev_err(priv->dev, "Failed to init IRQ!\n"); -+ goto out_dma; ++ aspeed_mctp_emit_tx_cmd(tx, packet); ++ aspeed_mctp_packet_free(packet); ++ trigger = true; ++ } + } -+ 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"); ++ spin_unlock(&priv->clients_lock); + -+ return 0; ++ if (trigger) ++ aspeed_mctp_tx_trigger(tx, full); ++} + -+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_rx_hdr_prep(struct aspeed_mctp *priv, u8 *hdr, u32 rx_lo) ++{ ++ u16 bdf; ++ u8 routing_type; ++ ++ /* ++ * MCTP controller will map the routing type to reduce one bit ++ * 0 (Route to RC) -> 0, ++ * 2 (Route by ID) -> 1, ++ * 3 (Broadcast from RC) -> 2 ++ */ ++ routing_type = FIELD_GET(RX_PACKET_ROUTING_TYPE, rx_lo); ++ routing_type = routing_type ? routing_type + 1 : 0; ++ bdf = _get_bdf(priv); ++ /* Length[7:0] */ ++ hdr[0] = FIELD_GET(RX_PACKET_SIZE, rx_lo); ++ /* TD:EP:ATTR[1:0]:R or AT[1:0]:Length[9:8] */ ++ hdr[1] = 0; ++ /* R or T9:TC[2:0]:R[3:0] */ ++ hdr[2] = 0; ++ /* R or Fmt[2]:Fmt[1:0]=b'11:Type[4:3]=b'10:Type[2:0] */ ++ hdr[3] = 0x70 | routing_type; ++ /* VDM message code = 0x7f */ ++ hdr[4] = 0x7f; ++ /* R[1:0]:Pad len[1:0]:MCTP VDM Code[3:0] */ ++ hdr[5] = FIELD_GET(RX_PACKET_PADDING_LEN, rx_lo) << 4; ++ /* TODO: PCI Requester ID: HW didn't get this information */ ++ hdr[6] = 0; ++ hdr[7] = 5; ++ /* Vendor ID: 0x1AB4 */ ++ hdr[8] = 0xb4; ++ hdr[9] = 0x1a; ++ /* PCI Target ID */ ++ hdr[10] = bdf & 0xff; ++ hdr[11] = bdf >> 8 & 0xff; ++ /* SOM:EOM:Pkt Seq#[1:0]:TO:Msg Tag[2:0]*/ ++ hdr[12] = FIELD_GET(RX_PACKET_SOM, rx_lo) << 7 | ++ FIELD_GET(RX_PACKET_EOM, rx_lo) << 6 | ++ FIELD_GET(RX_PACKET_SEQ_NUMBER, rx_lo) << 4 | ++ FIELD_GET(RX_PACKET_TAG_OWNER, rx_lo) << 3 | ++ FIELD_GET(RX_PACKET_MSG_TAG, rx_lo); ++ /* Source Endpoint ID */ ++ hdr[13] = FIELD_GET(RX_PACKET_SRC_EID, rx_lo); ++ /* Destination Endpoint ID: HW didn't get this information*/ ++ hdr[14] = priv->eid; ++ /* TODO: R[3:0]: header version[3:0] */ ++ hdr[15] = 1; +} + -+static void aspeed_mctp_remove(struct platform_device *pdev) ++static void aspeed_mctp_rx_tasklet(unsigned long data) +{ -+ struct aspeed_mctp *priv = platform_get_drvdata(pdev); ++ struct mctp_channel *rx = (struct mctp_channel *)data; ++ struct aspeed_mctp *priv = container_of(rx, typeof(*priv), rx); ++ struct mctp_pcie_packet *rx_packet; ++ struct aspeed_mctp_rx_cmd *rx_cmd; ++ u32 hw_read_ptr; ++ u32 *hdr, *payload; ++ bool rx_full; + -+#ifdef CONFIG_MCTP_TRANSPORT_PCIE_VDM -+ mctp_pcie_vdm_remove_dev(priv->ndev); -+#endif ++ /* initialized as false */ ++ rx_full = false; + -+ platform_device_unregister(priv->peci_mctp); ++ if (priv->match_data->vdm_hdr_direct_xfer && priv->match_data->fifo_auto_surround) { ++ struct mctp_pcie_packet_data *rx_buf; ++ u32 residual_cmds = 0; + -+ misc_deregister(&priv->mctp_miscdev); ++ /* Trigger HW read pointer update, must be done before RX loop */ ++ regmap_write(priv->map, ASPEED_MCTP_RX_BUF_RD_PTR, UPDATE_RX_RD_PTR); + -+ aspeed_mctp_irq_disable(priv); ++ /* ++ * rx->stopped indicates if rx ring is full or not. ++ * Use rx_full to note ring status before consuming packet. ++ */ ++ rx_full = rx->stopped; + -+ aspeed_mctp_dma_fini(priv); ++ /* ++ * XXX: Using rd_ptr obtained from HW is unreliable so we need to ++ * maintain the state of buffer on our own by peeking into the buffer ++ * and checking where the packet was written. ++ */ ++ rx_buf = (struct mctp_pcie_packet_data *)rx->data.vaddr; ++ hdr = (u32 *)&rx_buf[rx->wr_ptr]; ++ if (!*hdr && priv->rx_warmup) { ++ u32 tmp_wr_ptr = rx->wr_ptr; + -+ aspeed_mctp_drv_fini(priv); -+} ++ /* ++ * HACK: Right after start the RX hardware can put received ++ * packet into an unexpected offset - in order to locate ++ * received packet driver has to scan all RX data buffers. ++ */ ++ do { ++ tmp_wr_ptr = (tmp_wr_ptr + 1) % priv->rx_packet_count; + -+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, -+}; ++ hdr = (u32 *)&rx_buf[tmp_wr_ptr]; ++ } while (!*hdr && tmp_wr_ptr != rx->wr_ptr); + -+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, -+}; ++ if (tmp_wr_ptr != rx->wr_ptr) { ++ dev_warn(priv->dev, ++ "Runaway RX packet found %d -> %d\n", ++ rx->wr_ptr, tmp_wr_ptr); ++ residual_cmds = abs(tmp_wr_ptr - rx->wr_ptr); ++ rx->wr_ptr = tmp_wr_ptr; ++ if (!priv->rx_runaway_wa.enable && ++ priv->rx_warmup) ++ regmap_write(priv->map, ASPEED_MCTP_RX_BUF_SIZE, ++ rx->buffer_count - residual_cmds); ++ priv->rx_warmup = false; ++ } ++ } else { ++ priv->rx_warmup = false; ++ } + -+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, -+}; ++ if (priv->rx_runaway_wa.packet_counter > priv->rx_packet_count && ++ priv->rx_runaway_wa.first_loop) { ++ if (priv->rx_runaway_wa.enable) ++ /* ++ * Once we receive RX_PACKET_COUNT packets, hardware is ++ * guaranteed to use (RX_PACKET_COUNT - 4) buffers. Decrease ++ * buffer count by 4, then we can turn off scanning of RX ++ * buffers. RX buffer scanning should be enabled every time ++ * RX hardware is started. ++ * This is just a performance optimization - we could keep ++ * scanning RX buffers forever, but under heavy traffic it is ++ * fairly common that rx_tasklet is executed while RX buffer ++ * ring is empty. ++ */ ++ rx->buffer_count = priv->rx_packet_count - 4; ++ else ++ /* ++ * Once we receive RX_PACKET_COUNT packets, we need to restore the ++ * RX buffer size to 4 byte aligned value to avoid rx runaway. ++ */ ++ regmap_write(priv->map, ASPEED_MCTP_RX_BUF_SIZE, ++ rx->buffer_count); ++ priv->rx_runaway_wa.first_loop = false; ++ } + -+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, -+}; ++ while (*hdr != 0) { ++ if (FIELD_GET(MCTP_HDR_DW_LE_PACKET_SIZE, hdr[0]) * 4 > ++ ASPEED_MCTP_MTU) ++ dev_warn(priv->dev, ++ "Rx length %ld > MTU size %d\n", ++ FIELD_GET(MCTP_HDR_DW_LE_PACKET_SIZE, ++ hdr[0]) * ++ 4, ++ ASPEED_MCTP_MTU); ++ rx_packet = aspeed_mctp_packet_alloc(GFP_ATOMIC); ++ if (rx_packet) { ++ memcpy(&rx_packet->data, hdr, sizeof(rx_packet->data)); ++ aspeed_mctp_swap_pcie_vdm_hdr(&rx_packet->data); + -+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}, -+ { } -+}; ++ aspeed_mctp_dispatch_packet(priv, rx_packet); ++ } else { ++ dev_dbg(priv->dev, "Failed to allocate RX packet\n"); ++ } ++ data_dump(priv, &rx_packet->data); ++ *hdr = 0; ++ rx->wr_ptr = (rx->wr_ptr + 1) % rx->buffer_count; ++ hdr = (u32 *)&rx_buf[rx->wr_ptr]; + -+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, -+}; ++ priv->rx_runaway_wa.packet_counter++; ++ } + -+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; ++ /* ++ * Update HW write pointer, this can be done only after driver consumes ++ * packets from RX ring. ++ */ ++ regmap_read(priv->map, ASPEED_MCTP_RX_BUF_RD_PTR, &hw_read_ptr); ++ hw_read_ptr &= RX_BUF_RD_PTR_MASK; ++ regmap_write(priv->map, ASPEED_MCTP_RX_BUF_WR_PTR, (hw_read_ptr)); + -+ return platform_driver_register(&aspeed_mctp_driver); -+} ++ dev_dbg(priv->dev, "RX hw ptr %02d, sw ptr %2d\n", ++ hw_read_ptr, rx->wr_ptr); ++ } else { ++ struct mctp_pcie_packet_data_2500 *rx_buf; + -+static void __exit aspeed_mctp_exit(void) -+{ -+ platform_driver_unregister(&aspeed_mctp_driver); -+ kmem_cache_destroy(packet_cache); -+} ++ rx_buf = (struct mctp_pcie_packet_data_2500 *)rx->data.vaddr; ++ payload = (u32 *)&rx_buf[rx->wr_ptr]; ++ rx_cmd = (struct aspeed_mctp_rx_cmd *)rx->cmd.vaddr; ++ hdr = (u32 *)&((rx_cmd + rx->wr_ptr)->rx_lo); + -+module_init(aspeed_mctp_init) -+module_exit(aspeed_mctp_exit) ++ if (!*hdr) { ++ u32 tmp_wr_ptr = rx->wr_ptr; + -+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 2026-04-08 18:03:48.311705302 +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, - }; - - 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 2026-04-08 18:03:48.311705302 +0000 -@@ -0,0 +1,963 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+// Copyright (C) ASPEED Technology Inc. ++ /* ++ * HACK: Right after start the RX hardware can put received ++ * packet into an unexpected offset - in order to locate ++ * received packet driver has to scan all RX data buffers. ++ */ ++ do { ++ tmp_wr_ptr = (tmp_wr_ptr + 1) % rx->buffer_count; + -+#include -+#include -+#include -+#include ++ hdr = (u32 *)&((rx_cmd + tmp_wr_ptr)->rx_lo); ++ } while (!*hdr && tmp_wr_ptr != rx->wr_ptr); + -+#include -+#include -+#include -+#include -+#include -+#include ++ if (tmp_wr_ptr != rx->wr_ptr) { ++ dev_warn(priv->dev, ++ "Runaway RX packet found %d -> %d\n", ++ rx->wr_ptr, tmp_wr_ptr); ++ rx->wr_ptr = tmp_wr_ptr; ++ } ++ } + -+#include -+#include ++ while (*hdr != 0) { ++ rx_packet = aspeed_mctp_packet_alloc(GFP_ATOMIC); ++ if (rx_packet) { ++ memcpy(rx_packet->data.payload, payload, ++ sizeof(rx_packet->data.payload)); + -+#include -+#include -+#include -+#include -+#include -+#include ++ aspeed_mctp_rx_hdr_prep(priv, (u8 *)rx_packet->data.hdr, *hdr); + -+#include -+#include -+#include -+#include -+#include ++ aspeed_mctp_swap_pcie_vdm_hdr(&rx_packet->data); + -+#include "aspeed-pcie-mmbi.h" ++ aspeed_mctp_dispatch_packet(priv, rx_packet); ++ } else { ++ dev_dbg(priv->dev, "Failed to allocate RX packet\n"); ++ } ++ dev_dbg(priv->dev, ++ "rx->wr_ptr = %d, rx_cmd->rx_lo = %08x", ++ rx->wr_ptr, *hdr); ++ data_dump(priv, &rx_packet->data); ++ *hdr = 0; ++ rx->wr_ptr = (rx->wr_ptr + 1) % rx->buffer_count; ++ payload = (u32 *)&rx_buf[rx->wr_ptr]; ++ hdr = (u32 *)&((rx_cmd + rx->wr_ptr)->rx_lo); ++ } ++ } + -+/* 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 ++ /* Kick RX if it was stopped due to ring full condition */ ++ if (rx->stopped) { ++ if (!rx_full) { ++ /* ++ * RX ring may still be full in here as the HW keeps producing when Tasklet consumes the packets. ++ * Use rx_full to detect if RX ring is already full before or after Tasklet consumption. ++ * Schedule another tasklet here to consume RX ring before restarting reception if ring is full after the while loop, ++ * in case that RX_CMD_NO_MORE_INT interrupts tasklet after tasklet consumes packets. ++ * Use flag cause we cannot control if ASPEED_MCTP_RX_BUF_WR_PTR can be updated before ring full occurs. ++ * Example of problematic scenario: ++ * 1. Tasklet executing, found *hdr==0 at wr_ptr=14, break the while loop and going forward. ++ * 2. After leaving the loop, Tasklet spend time doing some time-consuming stuffs like printing log. ++ * 3. HW keep receiving during step2, and triggered RX_CMD_NO_MORE_INT to set rx->stopped to true in the IRQ handler. ++ * 4. CPU returns to Tasklet, after step2 the tasklet sees rx->stopped == true, therefore kick RX_READY to restart RX. ++ * 5. Issue reproduced, RX restarted without stored packets consumed, and get overwritten later. ++ */ ++ tasklet_hi_schedule(&priv->rx.tasklet); ++ } else { ++ rx->stopped = false; ++ regmap_update_bits(priv->map, ASPEED_MCTP_CTRL, RX_CMD_READY, ++ RX_CMD_READY); ++ } ++ } ++} + -+/* 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); -+}; ++static void aspeed_mctp_rx_chan_init(struct mctp_channel *rx) ++{ ++ struct aspeed_mctp *priv = container_of(rx, typeof(*priv), rx); ++ u32 *rx_cmd = (u32 *)rx->cmd.vaddr; ++ struct aspeed_mctp_rx_cmd *rx_cmd_64 = ++ (struct aspeed_mctp_rx_cmd *)rx->cmd.vaddr; ++ u32 data_size = priv->match_data->packet_unit_size; ++ u32 hw_rx_count = priv->rx_packet_count; ++ struct mctp_pcie_packet_data *rx_buf = (struct mctp_pcie_packet_data *)rx->data.vaddr; ++ int i; + -+struct aspeed_pcie_mmbi { -+ struct device *dev; -+ struct regmap *device; -+ struct regmap *e2m; -+ int irq; -+ const struct aspeed_platform *platform; -+ /* E2M index */ -+ int id; -+ int pid; -+ int scu_bar_offset; -+ int e2m_index; -+ int e2m_h2b_int; ++ if (priv->match_data->vdm_hdr_direct_xfer) { ++ if (priv->match_data->dma_need_64bits_width) { ++ for (i = 0; i < priv->rx_packet_count; i++) { ++ rx_cmd_64->rx_hi = ++ upper_32_bits((rx->data.dma_handle + data_size * i)); ++ rx_cmd_64->rx_lo = ++ (rx->data.dma_handle + data_size * i) & ++ GENMASK(31, 4); ++ rx_cmd_64->rx_lo |= RX_INTERRUPT_AFTER_CMD; ++ rx_cmd_64++; ++ } ++ } else { ++ for (i = 0; i < priv->rx_packet_count; i++) { ++ *rx_cmd = RX_DATA_ADDR(rx->data.dma_handle + data_size * i); ++ *rx_cmd |= RX_INTERRUPT_AFTER_CMD; ++ rx_cmd++; ++ } ++ } ++ } else { ++ for (i = 0; i < priv->rx_packet_count; i++) { ++ rx_cmd_64->rx_hi = RX_DATA_ADDR_2500(rx->data.dma_handle + data_size * i); ++ rx_cmd_64->rx_lo = 0; ++ if (i == priv->rx_packet_count - 1) ++ rx_cmd_64->rx_hi |= RX_LAST_CMD; ++ rx_cmd_64++; ++ } ++ } ++ /* Clear the header of rx data */ ++ for (i = 0; i < priv->rx_packet_count; i++) ++ *(u32 *)&rx_buf[i] = 0; ++ rx->wr_ptr = 0; ++ rx->buffer_count = priv->rx_packet_count; ++ if (priv->match_data->fifo_auto_surround) { ++ /* ++ * TODO: Once read pointer runaway bug is fixed in some future AST2x00 ++ * stepping then add chip revision detection and turn on this ++ * workaround only when needed ++ */ ++ if (priv->match_data->dma_need_64bits_width) ++ priv->rx_runaway_wa.enable = false; ++ else ++ priv->rx_runaway_wa.enable = ++ (chip_version(priv->dev) == ASPEED_MCTP_2600) ? ++ true : ++ false; + -+ /* Memory Mapping */ -+ void __iomem *mem_virt; -+ dma_addr_t mem_phy; -+ phys_addr_t mem_size; ++ /* ++ * Hardware does not wrap around ASPEED_MCTP_RX_BUF_SIZE ++ * correctly - we have to set number of buffers to n/4 -1 ++ */ ++ if (priv->rx_runaway_wa.enable) ++ hw_rx_count = (priv->rx_packet_count / 4 - 1); + -+ struct aspeed_mmbi_channel chan; -+}; ++ regmap_write(priv->map, ASPEED_MCTP_RX_BUF_SIZE, hw_rx_count); ++ } ++} + -+static void mmbi_desc_init(struct aspeed_mmbi_channel *chan); ++static void aspeed_mctp_tx_chan_init(struct mctp_channel *tx) ++{ ++ struct aspeed_mctp *priv = container_of(tx, typeof(*priv), tx); ++ ++ tx->wr_ptr = 0; ++ tx->rd_ptr = 0; ++ regmap_update_bits(priv->map, ASPEED_MCTP_CTRL, TX_CMD_TRIGGER, 0); ++ regmap_write(priv->map, ASPEED_MCTP_TX_BUF_ADDR, tx->cmd.dma_handle); ++ if (priv->match_data->dma_need_64bits_width) ++ regmap_write(priv->map, ASPEED_MCTP_TX_BUF_HI_ADDR, ++ upper_32_bits(tx->cmd.dma_handle)); ++ if (priv->match_data->fifo_auto_surround) { ++ regmap_write(priv->map, ASPEED_MCTP_TX_BUF_SIZE, TX_PACKET_COUNT); ++ regmap_write(priv->map, ASPEED_MCTP_TX_BUF_WR_PTR, 0); ++ } ++} + -+static u8 mmbi_get_bmc_up(struct aspeed_mmbi_channel *chan) ++struct mctp_client *aspeed_mctp_create_client(struct aspeed_mctp *priv) +{ -+ struct host_ros hros; -+ -+ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); ++ struct mctp_client *client; + -+ return hros.b_up; -+} ++ client = aspeed_mctp_client_alloc(priv); ++ if (!client) ++ return NULL; + -+static u8 mmbi_get_bmc_rdy(struct aspeed_mmbi_channel *chan) -+{ -+ struct host_ros hros; ++ init_waitqueue_head(&client->wait_queue); + -+ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); ++ spin_lock_bh(&priv->clients_lock); ++ list_add_tail(&client->link, &priv->clients); ++ spin_unlock_bh(&priv->clients_lock); + -+ return hros.b_rdy; ++ return client; +} ++EXPORT_SYMBOL_GPL(aspeed_mctp_create_client); + -+static u8 mmbi_get_bmc_rst(struct aspeed_mmbi_channel *chan) ++static int aspeed_mctp_open(struct inode *inode, struct file *file) +{ -+ struct host_ros hros; ++ struct miscdevice *misc = file->private_data; ++ struct platform_device *pdev = to_platform_device(misc->parent); ++ struct aspeed_mctp *priv = platform_get_drvdata(pdev); ++ struct mctp_client *client; + -+ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); ++ client = aspeed_mctp_create_client(priv); ++ if (!client) ++ return -ENOMEM; + -+ return hros.b_rst; ++ file->private_data = client; ++ ++ return 0; +} + -+static u8 mmbi_get_host_rst(struct aspeed_mmbi_channel *chan) ++void aspeed_mctp_delete_client(struct mctp_client *client) +{ -+ struct host_rws hrws; ++ struct aspeed_mctp *priv = client->priv; ++ struct mctp_type_handler *handler, *tmp; + -+ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); ++ spin_lock_bh(&priv->clients_lock); + -+ return hrws.h_rst; -+} ++ list_del(&client->link); + -+static u8 mmbi_get_host_rdy(struct aspeed_mmbi_channel *chan) -+{ -+ struct host_rws hrws; ++ if (priv->default_client == client) ++ priv->default_client = NULL; + -+ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); ++ list_for_each_entry_safe(handler, tmp, &priv->mctp_type_handlers, ++ link) { ++ if (handler->client == client) { ++ list_del(&handler->link); ++ kfree(handler); ++ } ++ } ++ spin_unlock_bh(&priv->clients_lock); + -+ return hrws.h_rdy; ++ /* Disable the tasklet to appease lockdep */ ++ local_bh_disable(); ++ aspeed_mctp_client_put(client); ++ local_bh_enable(); +} ++EXPORT_SYMBOL_GPL(aspeed_mctp_delete_client); + -+static u8 mmbi_get_host_up(struct aspeed_mmbi_channel *chan) ++static int aspeed_mctp_release(struct inode *inode, struct file *file) +{ -+ struct host_rws hrws; ++ struct mctp_client *client = file->private_data; + -+ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); ++ aspeed_mctp_delete_client(client); + -+ return hrws.h_up; ++ return 0; +} + -+static void mmbi_set_bmc_rst(struct aspeed_mmbi_channel *chan, bool set) -+{ -+ struct host_ros hros; -+ -+ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); -+ hros.b_rst = set; -+ memcpy_toio(chan->hros_vmem, &hros, sizeof(hros)); -+} ++#define LEN_MASK_HI GENMASK(9, 8) ++#define LEN_MASK_LO GENMASK(7, 0) ++#define PCI_VDM_HDR_LEN_MASK_LO GENMASK(31, 24) ++#define PCI_VDM_HDR_LEN_MASK_HI GENMASK(17, 16) ++#define PCIE_VDM_HDR_REQUESTER_BDF_MASK GENMASK(31, 16) + -+static void mmbi_set_bmc_rdy(struct aspeed_mmbi_channel *chan, bool set) ++int aspeed_mctp_send_packet(struct mctp_client *client, ++ struct mctp_pcie_packet *packet) +{ -+ struct host_ros hros; ++ struct aspeed_mctp *priv = client->priv; ++ u32 *hdr_dw = (u32 *)packet->data.hdr; ++ u8 *hdr = (u8 *)packet->data.hdr; ++ u8 *payload = (u8 *)packet->data.payload; ++ u16 packet_data_sz_dw; ++ u16 pci_data_len_dw; ++ int ret; ++ u16 bdf; + -+ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); -+ hros.b_rdy = set; -+ memcpy_toio(chan->hros_vmem, &hros, sizeof(hros)); -+} ++ ret = _get_bdf(priv); ++ if (ret < 0) ++ return ret; ++ bdf = ret; + -+static void mmbi_set_bmc_up(struct aspeed_mmbi_channel *chan, bool set) -+{ -+ struct host_ros hros; ++ /* ++ * If the data size is different from contents of PCIe VDM header, ++ * aspeed_mctp_tx_cmd will be programmed incorrectly. This may cause ++ * MCTP HW to stop working. ++ */ ++ pci_data_len_dw = FIELD_PREP(LEN_MASK_LO, FIELD_GET(PCI_VDM_HDR_LEN_MASK_LO, hdr_dw[0])) | ++ FIELD_PREP(LEN_MASK_HI, FIELD_GET(PCI_VDM_HDR_LEN_MASK_HI, hdr_dw[0])); ++ if (pci_data_len_dw == 0) /* According to PCIe Spec, 0 means 1024 DW */ ++ pci_data_len_dw = SZ_1K; + -+ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); -+ hros.b_up = set; -+ memcpy_toio(chan->hros_vmem, &hros, sizeof(hros)); -+} ++ packet_data_sz_dw = packet->size / sizeof(u32) - sizeof(packet->data.hdr) / sizeof(u32); ++ if (packet_data_sz_dw != pci_data_len_dw) ++ return -EINVAL; + -+static void raise_b2h_interrupt(struct aspeed_mmbi_channel *chan) -+{ -+ if (!chan->host_int_en) -+ return; ++ be32p_replace_bits(&hdr_dw[1], bdf, PCIE_VDM_HDR_REQUESTER_BDF_MASK); + -+ regmap_write(chan->mmbi->e2m, ASPEED_E2M_EVENT_SET, BIT(chan->mmbi->e2m_h2b_int)); -+} ++ /* ++ * XXX Don't update EID for MCTP Control messages - old EID may ++ * interfere with MCTP discovery flow. ++ */ ++ if (priv->eid && payload[MCTP_PAYLOAD_TYPE_OFFSET] != MCTP_HDR_TYPE_CONTROL) ++ hdr[MCTP_HDR_SRC_EID_OFFSET] = priv->eid; + -+static void mmbi_clear_hros(struct aspeed_mmbi_channel *chan) -+{ -+ memset_io(chan->hros_vmem, 0, sizeof(struct host_ros)); -+} ++ ret = ptr_ring_produce_bh(&client->tx_queue, packet); ++ if (!ret) ++ tasklet_hi_schedule(&priv->tx.tasklet); + -+static void mmbi_clear_hrws(struct aspeed_mmbi_channel *chan) -+{ -+ memset_io(chan->hrws_vmem, 0, sizeof(struct host_rws)); ++ return ret; +} ++EXPORT_SYMBOL_GPL(aspeed_mctp_send_packet); + -+static void get_b2h_avail_buf_len(struct aspeed_mmbi_channel *chan, ssize_t *avail_buf_len) ++struct mctp_pcie_packet *aspeed_mctp_receive_packet(struct mctp_client *client, ++ unsigned long timeout) +{ -+ struct device *dev = chan->dev; -+ u32 b2h_rp, b2h_wp; ++ struct aspeed_mctp *priv = client->priv; ++ int ret; + -+ 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); ++ ret = _get_bdf(priv); ++ if (ret < 0) ++ return ERR_PTR(ret); + -+ if (b2h_wp >= b2h_rp) -+ *avail_buf_len = chan->b2h_cb_size - b2h_wp + b2h_rp; -+ else -+ *avail_buf_len = b2h_rp - b2h_wp; ++ 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); ++ ++ return ptr_ring_consume_bh(&client->rx_queue); +} ++EXPORT_SYMBOL_GPL(aspeed_mctp_receive_packet); + -+static u8 mmbi_get_state(struct aspeed_mmbi_channel *chan) ++void aspeed_mctp_flush_rx_queue(struct mctp_client *client) +{ -+ 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); ++ struct mctp_pcie_packet *packet; + -+ return state; ++ while ((packet = ptr_ring_consume_bh(&client->rx_queue))) ++ aspeed_mctp_packet_free(packet); +} ++EXPORT_SYMBOL_GPL(aspeed_mctp_flush_rx_queue); + -+static int get_mmbi_header(struct aspeed_mmbi_channel *chan, u32 *data_length, -+ u8 *type, u32 *unread_data_len, u8 *padding) ++static ssize_t aspeed_mctp_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) +{ -+ u32 h2b_wp, h2b_rp, b2h_wp, b2h_rp; -+ struct device *dev = chan->dev; -+ struct mmbi_header header; ++ struct mctp_client *client = file->private_data; ++ struct aspeed_mctp *priv = client->priv; ++ struct mctp_pcie_packet *rx_packet; ++ u32 mctp_ctrl; ++ u32 mctp_int_sts; + -+ 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); ++ if (count < PCIE_MCTP_MIN_PACKET_SIZE) ++ return -EINVAL; + -+ if (h2b_wp >= h2b_rp) -+ *unread_data_len = h2b_wp - h2b_rp; -+ else -+ *unread_data_len = chan->h2b_cb_size - h2b_rp + h2b_wp; ++ if (count > sizeof(rx_packet->data)) ++ count = sizeof(rx_packet->data); + -+ if (*unread_data_len < sizeof(struct mmbi_header)) { -+ dev_dbg(dev, "No data to read(%d - %d)\n", h2b_wp, h2b_rp); -+ return -EAGAIN; ++ if (priv->miss_mctp_int) { ++ regmap_read(priv->map, ASPEED_MCTP_CTRL, &mctp_ctrl); ++ if (!(mctp_ctrl & RX_CMD_READY)) ++ priv->rx.stopped = true; ++ /* Polling the RX_CMD_RECEIVE_INT to ensure rx_tasklet can find the data */ ++ regmap_read(priv->map, ASPEED_MCTP_INT_STS, &mctp_int_sts); ++ if (mctp_int_sts & RX_CMD_RECEIVE_INT) ++ regmap_write(priv->map, ASPEED_MCTP_INT_STS, ++ mctp_int_sts); + } + -+ dev_dbg(dev, "READ MMBI header from: 0x%lx\n", -+ (ssize_t)(chan->h2b_cb_vmem + h2b_rp)); -+ -+ /* 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; ++ tasklet_hi_schedule(&priv->rx.tasklet); ++ rx_packet = ptr_ring_consume_bh(&client->rx_queue); ++ if (!rx_packet) ++ return -EAGAIN; + -+ 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); ++ if (copy_to_user(buf, &rx_packet->data, count)) { ++ dev_err(priv->dev, "copy to user failed\n"); ++ count = -EFAULT; + } + -+ *data_length = (header.pkt_len << 2) - sizeof(header) - header.pkt_pad; -+ *padding = header.pkt_pad; -+ *type = header.pkt_type; ++ aspeed_mctp_packet_free(rx_packet); + -+ return 0; ++ return count; +} + -+static int mmbi_state_check(struct aspeed_mmbi_channel *chan) ++static void aspeed_mctp_flush_tx_queue(struct mctp_client *client) +{ -+ 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; -+ } ++ struct mctp_pcie_packet *packet; + -+ return 0; ++ while ((packet = ptr_ring_consume_bh(&client->tx_queue))) ++ aspeed_mctp_packet_free(packet); +} + -+static void update_host_ros(struct aspeed_mmbi_channel *chan, unsigned int w_len, -+ unsigned int r_len) ++static void aspeed_mctp_flush_all_tx_queues(struct aspeed_mctp *priv) +{ -+ 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); ++ struct mctp_client *client; + -+ if (w_len != 0) -+ raise_b2h_interrupt(chan); ++ spin_lock_bh(&priv->clients_lock); ++ list_for_each_entry(client, &priv->clients, link) ++ aspeed_mctp_flush_tx_queue(client); ++ spin_unlock_bh(&priv->clients_lock); +} + -+static int aspeed_mmbi_write(struct aspeed_mmbi_channel *chan, char *buffer, size_t len, -+ protocol_type type) ++static ssize_t aspeed_mctp_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) +{ -+ 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; ++ struct mctp_client *client = file->private_data; ++ struct aspeed_mctp *priv = client->priv; ++ struct mctp_pcie_packet *tx_packet; ++ int ret; + -+ /* 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; -+ } ++ if (count < PCIE_MCTP_MIN_PACKET_SIZE) ++ return -EINVAL; + -+ get_b2h_avail_buf_len(chan, &avail_buf_len); ++ if (count > sizeof(tx_packet->data)) ++ return -ENOSPC; + -+ dev_dbg(dev, "B2H buffer empty space: %ld\n", avail_buf_len); ++ tx_packet = aspeed_mctp_packet_alloc(GFP_KERNEL); ++ if (!tx_packet) { ++ ret = -ENOMEM; ++ goto out; ++ } + -+ /* Header size */ -+ total_len = len + 4; ++ if (copy_from_user(&tx_packet->data, buf, count)) { ++ dev_err(priv->dev, "copy from user failed\n"); ++ ret = -EFAULT; ++ goto out_packet; ++ } + -+ padding = total_len & 0x3; -+ if (padding) -+ padding = 4 - padding; -+ total_len += padding; ++ tx_packet->size = count; + -+ /* 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; ++ ret = aspeed_mctp_send_packet(client, tx_packet); ++ if (ret) ++ goto out_packet; + -+ /* Fill multi-protocol header */ -+ header.pkt_type = type; -+ header.pkt_len = total_len >> 2; -+ header.pkt_pad = padding; ++ return count; + -+ wt_offset = GET_B2H_WRITE_POINTER(chan); -+ end_offset = chan->b2h_cb_size; ++out_packet: ++ aspeed_mctp_packet_free(tx_packet); ++out: ++ return ret; ++} + -+ /* Copy Header */ -+ if ((end_offset - wt_offset) >= sizeof(header)) { -+ memcpy_toio(chan->b2h_cb_vmem + wt_offset, &header, sizeof(header)); -+ wt_offset += sizeof(header); ++int aspeed_mctp_add_type_handler(struct mctp_client *client, u8 mctp_type, ++ u16 pci_vendor_id, u16 vdm_type, u16 vdm_mask) ++{ ++ struct aspeed_mctp *priv = client->priv; ++ struct mctp_type_handler *handler, *new_handler; ++ int ret = 0; ++ ++ if (mctp_type <= MCTP_HDR_TYPE_BASE_LAST) { ++ /* Vendor, type and type mask must be zero for types 0-5 */ ++ if (pci_vendor_id != 0 || vdm_type != 0 || vdm_mask != 0) ++ return -EINVAL; ++ } else if (mctp_type == MCTP_HDR_TYPE_VDM_PCI) { ++ /* For Vendor Defined PCI type the vendor ID must be nonzero */ ++ if (pci_vendor_id == 0 || pci_vendor_id == 0xffff) ++ return -EINVAL; + } 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); ++ return -EINVAL; + } + -+ /* 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); ++ new_handler = kzalloc(sizeof(*new_handler), GFP_KERNEL); ++ if (!new_handler) ++ return -ENOMEM; ++ new_handler->mctp_type = mctp_type; ++ new_handler->pci_vendor_id = pci_vendor_id; ++ new_handler->vdm_type = vdm_type & vdm_mask; ++ new_handler->vdm_mask = vdm_mask; ++ new_handler->client = client; + -+ wt_offset = 0; -+ memcpy_toio(&chan->b2h_cb_vmem[wt_offset], buffer + chunk_len, len - chunk_len); -+ wt_offset += len - chunk_len; ++ spin_lock_bh(&priv->clients_lock); ++ list_for_each_entry(handler, &priv->mctp_type_handlers, link) { ++ if (handler->mctp_type == new_handler->mctp_type && ++ handler->pci_vendor_id == new_handler->pci_vendor_id && ++ handler->vdm_type == new_handler->vdm_type) { ++ if (handler->client != new_handler->client) ++ ret = -EBUSY; ++ kfree(new_handler); ++ goto out_unlock; ++ } + } ++ list_add_tail(&new_handler->link, &priv->mctp_type_handlers); ++out_unlock: ++ spin_unlock_bh(&priv->clients_lock); + -+ update_host_ros(chan, total_len, 0); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(aspeed_mctp_add_type_handler); + -+ return 0; ++static int aspeed_mctp_remove_type_handler(struct mctp_client *client, ++ u8 mctp_type, u16 pci_vendor_id, ++ u16 vdm_type, u16 vdm_mask) ++{ ++ struct aspeed_mctp *priv = client->priv; ++ struct mctp_type_handler *handler, *tmp; ++ int ret = -EINVAL; ++ ++ vdm_type &= vdm_mask; ++ ++ spin_lock_bh(&priv->clients_lock); ++ list_for_each_entry_safe(handler, tmp, &priv->mctp_type_handlers, ++ link) { ++ if (handler->client == client && ++ handler->mctp_type == mctp_type && ++ handler->pci_vendor_id == pci_vendor_id && ++ handler->vdm_type == vdm_type) { ++ list_del(&handler->link); ++ kfree(handler); ++ ret = 0; ++ break; ++ } ++ } ++ spin_unlock_bh(&priv->clients_lock); ++ return ret; +} + -+static void aspeed_mmbi_read(struct aspeed_mmbi_channel *chan, char *buffer, size_t len, u8 padding) ++int aspeed_mctp_register_default_handler(struct mctp_client *client) +{ -+ struct device *dev = chan->dev; -+ ssize_t rd_offset; -+ u32 h2b_rp; ++ struct aspeed_mctp *priv = client->priv; ++ int ret = 0; + -+ 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; ++ spin_lock_bh(&priv->clients_lock); + -+ /* 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 (!priv->default_client) ++ priv->default_client = client; ++ else if (priv->default_client != client) ++ ret = -EBUSY; + -+ 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; ++ spin_unlock_bh(&priv->clients_lock); + -+ 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); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(aspeed_mctp_register_default_handler); + -+ rd_offset = 0; -+ memcpy_fromio(buffer + chunk_len, chan->h2b_cb_vmem + rd_offset, len - chunk_len); ++static int ++aspeed_mctp_register_type_handler(struct mctp_client *client, ++ void __user *userbuf) ++{ ++ struct aspeed_mctp *priv = client->priv; ++ struct aspeed_mctp_type_handler_ioctl handler; ++ ++ if (copy_from_user(&handler, userbuf, sizeof(handler))) { ++ dev_err(priv->dev, "copy from user failed\n"); ++ return -EFAULT; + } + -+ update_host_ros(chan, 0, len + sizeof(struct mmbi_header) + padding); ++ return aspeed_mctp_add_type_handler(client, handler.mctp_type, ++ handler.pci_vendor_id, ++ handler.vendor_type, ++ handler.vendor_type_mask); +} + -+static void mctp_mmbi_rx(struct aspeed_mmbi_channel *chan) ++static int ++aspeed_mctp_unregister_type_handler(struct mctp_client *client, ++ void __user *userbuf) +{ -+ 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; -+ -+ 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); ++ struct aspeed_mctp *priv = client->priv; ++ struct aspeed_mctp_type_handler_ioctl handler; + -+ 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; ++ if (copy_from_user(&handler, userbuf, sizeof(handler))) { ++ dev_err(priv->dev, "copy from user failed\n"); ++ return -EFAULT; + } + -+ 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); ++ return aspeed_mctp_remove_type_handler(client, handler.mctp_type, ++ handler.pci_vendor_id, ++ handler.vendor_type, ++ handler.vendor_type_mask); ++} + -+ cb = __mctp_cb(skb); -+ cb->halen = 0; ++static int ++aspeed_mctp_filter_eid(struct aspeed_mctp *priv, void __user *userbuf) ++{ ++ struct aspeed_mctp_filter_eid eid; + -+ status = netif_rx(skb); -+ if (status == NET_RX_SUCCESS) { -+ ndev->stats.rx_packets++; -+ ndev->stats.rx_bytes += req_data_len; ++ if (copy_from_user(&eid, userbuf, sizeof(eid))) { ++ dev_err(priv->dev, "copy from user failed\n"); ++ return -EFAULT; ++ } ++ ++ if (eid.enable) { ++ regmap_update_bits(priv->map, ASPEED_MCTP_EID, ++ MCTP_EID, eid.eid); ++ regmap_update_bits(priv->map, ASPEED_MCTP_CTRL, ++ MATCHING_EID, MATCHING_EID); + } else { -+ ndev->stats.rx_dropped++; ++ regmap_update_bits(priv->map, ASPEED_MCTP_CTRL, ++ MATCHING_EID, 0); + } ++ return 0; +} + -+static netdev_tx_t mctp_mmbi_tx(struct sk_buff *skb, struct net_device *ndev) ++static int aspeed_mctp_get_bdf(struct aspeed_mctp *priv, void __user *userbuf) +{ -+ struct aspeed_mmbi_mctp *mctp = netdev_priv(ndev); -+ int ret; ++ struct aspeed_mctp_get_bdf bdf = { _get_bdf(priv) }; + -+ if (!mmbi_get_host_rdy(&mctp->mmbi->chan) || skb->len > MCTP_MMBI_MTU_MAX) { -+ ndev->stats.tx_dropped++; -+ goto out; ++ if (copy_to_user(userbuf, &bdf, sizeof(bdf))) { ++ dev_err(priv->dev, "copy to user failed\n"); ++ return -EFAULT; + } ++ return 0; ++} + -+ ret = aspeed_mmbi_write(&mctp->mmbi->chan, skb->data, skb->len, MMBI_PROTOCOL_MCTP); -+ if (ret) { -+ netif_stop_queue(ndev); -+ return NETDEV_TX_BUSY; -+ } ++static int ++aspeed_mctp_get_medium_id(struct aspeed_mctp *priv, void __user *userbuf) ++{ ++ struct aspeed_mctp_get_medium_id id = { 0x09 }; /* PCIe revision 2.0 */ + -+ ndev->stats.tx_packets++; -+ ndev->stats.tx_bytes += skb->len; -+out: -+ kfree_skb(skb); -+ return NETDEV_TX_OK; ++ if (copy_to_user(userbuf, &id, sizeof(id))) { ++ dev_err(priv->dev, "copy to user failed\n"); ++ return -EFAULT; ++ } ++ return 0; +} + -+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) ++static int ++aspeed_mctp_get_mtu(struct aspeed_mctp *priv, void __user *userbuf) +{ -+ 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; ++ struct aspeed_mctp_get_mtu id = { ASPEED_MCTP_MTU }; + -+ 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; ++ if (copy_to_user(userbuf, &id, sizeof(id))) { ++ dev_err(priv->dev, "copy to user failed\n"); ++ return -EFAULT; ++ } ++ return 0; +} + -+static int aspeed_mmbi_mctp_init(struct aspeed_mmbi_channel *chan) ++int aspeed_mctp_get_eid_bdf(struct mctp_client *client, u8 eid, u16 *bdf) +{ -+ 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; ++ struct aspeed_mctp_endpoint *endpoint; ++ int ret = -ENOENT; + -+ mctp = netdev_priv(ndev); -+ mctp->ndev = ndev; -+ mctp->mmbi = chan->mmbi; ++ mutex_lock(&client->priv->endpoints_lock); ++ list_for_each_entry(endpoint, &client->priv->endpoints, link) { ++ if (endpoint->data.eid_info.eid == eid) { ++ *bdf = endpoint->data.eid_info.bdf; ++ ret = 0; ++ break; ++ } ++ } ++ mutex_unlock(&client->priv->endpoints_lock); + -+ chan->ndev = ndev; ++ return ret; ++} ++EXPORT_SYMBOL_GPL(aspeed_mctp_get_eid_bdf); + -+ ret = register_netdev(ndev); -+ if (ret) -+ goto free_netdev; ++int aspeed_mctp_get_eid(struct mctp_client *client, u16 bdf, ++ u8 domain_id, u8 *eid) ++{ ++ struct aspeed_mctp_endpoint *endpoint; ++ int ret = -ENOENT; + -+ return 0; ++ mutex_lock(&client->priv->endpoints_lock); + -+free_netdev: -+ free_netdev(ndev); ++ list_for_each_entry(endpoint, &client->priv->endpoints, link) { ++ if (endpoint->data.eid_ext_info.domain_id == domain_id && ++ endpoint->data.eid_ext_info.bdf == bdf) { ++ *eid = endpoint->data.eid_ext_info.eid; ++ ret = 0; ++ break; ++ } ++ } + ++ mutex_unlock(&client->priv->endpoints_lock); + return ret; +} ++EXPORT_SYMBOL_GPL(aspeed_mctp_get_eid); + -+static void aspeed_mmbi_work_func(struct work_struct *workq) ++static int ++aspeed_mctp_get_eid_info(struct aspeed_mctp *priv, void __user *userbuf, ++ enum mctp_address_type addr_format) +{ -+ 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; ++ int count = 0; ++ int ret = 0; ++ struct aspeed_mctp_get_eid_info get_eid; ++ struct aspeed_mctp_endpoint *endpoint; ++ void *user_ptr; ++ size_t count_to_copy; + -+ for (i = 0; i < weight; i++) { -+ if (get_mmbi_header(chan, &req_data_len, &type, &unread_data_len, &padding) != 0) -+ return; ++ if (copy_from_user(&get_eid, userbuf, sizeof(get_eid))) { ++ dev_err(priv->dev, "copy from user failed\n"); ++ return -EFAULT; ++ } + -+ dev_dbg(chan->dev, "%s: Length: 0x%0x, Protocol Type: %d\n", -+ __func__, req_data_len, type); ++ mutex_lock(&priv->endpoints_lock); + -+ if (type == MMBI_PROTOCOL_MCTP) -+ mctp_mmbi_rx(chan); ++ if (get_eid.count == 0) { ++ count = priv->endpoints_count; ++ goto out_unlock; ++ } ++ ++ user_ptr = u64_to_user_ptr(get_eid.ptr); ++ count_to_copy = get_eid.count > priv->endpoints_count ? ++ priv->endpoints_count : get_eid.count; ++ list_for_each_entry(endpoint, &priv->endpoints, link) { ++ if (endpoint->data.eid_info.eid < get_eid.start_eid) ++ continue; ++ if (count >= count_to_copy) ++ break; ++ ++ if (addr_format == ASPEED_MCTP_EXTENDED_ADDR_FORMAT) ++ ret = copy_to_user(&(((struct aspeed_mctp_eid_ext_info *) ++ user_ptr)[count]), ++ &endpoint->data, ++ sizeof(struct aspeed_mctp_eid_ext_info)); + else -+ /* Discard data and advance the hrws */ -+ update_host_ros(chan, 0, req_data_len + sizeof(struct mmbi_header) + padding); ++ ret = copy_to_user(&(((struct aspeed_mctp_eid_info *) ++ user_ptr)[count]), ++ &endpoint->data, ++ sizeof(struct aspeed_mctp_eid_info)); + -+ raise_b2h_interrupt(chan); ++ if (ret) { ++ dev_err(priv->dev, "copy to user failed\n"); ++ ret = -EFAULT; ++ goto out_unlock; ++ } ++ count++; + } + -+ if (get_mmbi_header(chan, &req_data_len, &type, &unread_data_len, &padding) != 0) -+ queue_work(system_unbound_wq, &chan->work); ++out_unlock: ++ get_eid.count = count; ++ if (copy_to_user(userbuf, &get_eid, sizeof(get_eid))) { ++ dev_err(priv->dev, "copy to user failed\n"); ++ ret = -EFAULT; ++ } ++ ++ mutex_unlock(&priv->endpoints_lock); ++ return ret; +} + -+static irqreturn_t aspeed_pcie_mmbi_isr(int irq, void *dev_id) ++static int ++eid_info_cmp(void *priv, const struct list_head *a, const struct list_head *b) +{ -+ struct aspeed_pcie_mmbi *mmbi = dev_id; -+ struct aspeed_mmbi_channel *chan = &mmbi->chan; -+ ssize_t avail_buf_len; ++ struct aspeed_mctp_endpoint *endpoint_a; ++ struct aspeed_mctp_endpoint *endpoint_b; + -+ 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); -+ } -+ } ++ if (a == b) ++ return 0; + -+ if (mmbi_state_check(chan)) -+ return IRQ_HANDLED; ++ endpoint_a = list_entry(a, typeof(*endpoint_a), link); ++ endpoint_b = list_entry(b, typeof(*endpoint_b), link); + -+ queue_work(system_unbound_wq, &chan->work); ++ if (endpoint_a->data.eid_info.eid < endpoint_b->data.eid_info.eid) ++ return -1; ++ else if (endpoint_a->data.eid_info.eid > endpoint_b->data.eid_info.eid) ++ return 1; + -+ return IRQ_HANDLED; ++ return 0; +} + -+static void mmbi_desc_init(struct aspeed_mmbi_channel *chan) ++static void aspeed_mctp_eid_info_list_remove(struct list_head *list) +{ -+ struct mmbi_cap_desc desc; ++ struct aspeed_mctp_endpoint *endpoint; ++ struct aspeed_mctp_endpoint *tmp; + -+ memset(&desc, 0, sizeof(struct mmbi_cap_desc)); ++ list_for_each_entry_safe(endpoint, tmp, list, link) { ++ list_del(&endpoint->link); ++ kfree(endpoint); ++ } ++} + -+ 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; ++static bool ++aspeed_mctp_eid_info_list_valid(struct list_head *list) ++{ ++ struct aspeed_mctp_endpoint *endpoint; ++ struct aspeed_mctp_endpoint *next; + -+ /* Per MMBI protoco spec, Set it to "#MMBI$" */ -+ memcpy(desc.signature, MMBI_SIGNATURE, sizeof(desc.signature)); ++ list_for_each_entry(endpoint, list, link) { ++ next = list_next_entry(endpoint, link); ++ if (&next->link == list) ++ break; + -+ memcpy_toio(chan->desc_vmem, &desc, sizeof(desc)); ++ /* duplicted eids */ ++ if (next->data.eid_info.eid == endpoint->data.eid_info.eid) ++ return false; ++ } ++ ++ return true; +} + -+static int aspeed_pcie_mmbi_init(struct aspeed_pcie_mmbi *mmbi) ++static int ++aspeed_mctp_set_eid_info(struct aspeed_mctp *priv, void __user *userbuf, ++ enum mctp_address_type addr_format) +{ -+ 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; ++ struct list_head list = LIST_HEAD_INIT(list); ++ struct aspeed_mctp_set_eid_info set_eid; ++ void *user_ptr; ++ struct aspeed_mctp_endpoint *endpoint; ++ int ret = 0; ++ u8 eid = 0; ++ size_t i; + -+ b2h_vaddr = mmbi->mem_virt; -+ h2b_vaddr = b2h_vaddr + b2h_size; ++ if (copy_from_user(&set_eid, userbuf, sizeof(set_eid))) { ++ dev_err(priv->dev, "copy from user failed\n"); ++ return -EFAULT; ++ } + -+ 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); ++ if (set_eid.count > ASPEED_MCTP_EID_INFO_MAX) ++ return -EINVAL; + -+ 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); ++ user_ptr = u64_to_user_ptr(set_eid.ptr); ++ for (i = 0; i < set_eid.count; i++) { ++ endpoint = kzalloc(sizeof(*endpoint), GFP_KERNEL); ++ if (!endpoint) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ memset(endpoint, 0, sizeof(*endpoint)); + -+ 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); ++ if (addr_format == ASPEED_MCTP_EXTENDED_ADDR_FORMAT) ++ ret = copy_from_user(&endpoint->data, ++ &(((struct aspeed_mctp_eid_ext_info *) ++ user_ptr)[i]), ++ sizeof(struct aspeed_mctp_eid_ext_info)); ++ else ++ ret = copy_from_user(&endpoint->data, ++ &(((struct aspeed_mctp_eid_info *) ++ user_ptr)[i]), ++ sizeof(struct aspeed_mctp_eid_info)); + -+ 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); ++ if (ret) { ++ dev_err(priv->dev, "copy from user failed\n"); ++ kfree(endpoint); ++ ret = -EFAULT; ++ goto out; ++ } + -+ /* Initialize the MMBI channel descriptor */ -+ mmbi_desc_init(chan); ++ /* Detect self EID */ ++ if (_get_bdf(priv) == endpoint->data.eid_info.bdf) { ++ /* ++ * XXX Use smallest EID with matching BDF. ++ * On some platforms there could be multiple endpoints ++ * with same BDF in routing table. ++ */ ++ if (eid == 0 || endpoint->data.eid_info.eid < eid) ++ eid = endpoint->data.eid_info.eid; ++ } + -+ /* Clear HRWS & HROS */ -+ mmbi_clear_hros(chan); -+ mmbi_clear_hrws(chan); ++ list_add_tail(&endpoint->link, &list); ++ } + -+ /* Initialize MTCP function */ -+ ret = aspeed_mmbi_mctp_init(chan); -+ if (ret) { -+ dev_err(dev, "Unable to init mctp\n"); -+ return ret; ++ list_sort(NULL, &list, eid_info_cmp); ++ if (!aspeed_mctp_eid_info_list_valid(&list)) { ++ ret = -EINVAL; ++ goto out; + } + -+ /* Set BMC UP bit */ -+ mmbi_set_bmc_up(chan, 1); ++ mutex_lock(&priv->endpoints_lock); ++ if (list_empty(&priv->endpoints)) ++ list_splice_init(&list, &priv->endpoints); ++ else ++ list_swap(&list, &priv->endpoints); ++ priv->endpoints_count = set_eid.count; ++ priv->eid = eid; ++ mutex_unlock(&priv->endpoints_lock); ++out: ++ aspeed_mctp_eid_info_list_remove(&list); ++ return ret; ++} ++ ++static int aspeed_mctp_set_own_eid(struct aspeed_mctp *priv, void __user *userbuf) ++{ ++ struct aspeed_mctp_set_own_eid data; ++ ++ if (copy_from_user(&data, userbuf, sizeof(data))) { ++ dev_err(priv->dev, "copy from user failed\n"); ++ return -EFAULT; ++ } ++ ++ priv->eid = data.eid; + + return 0; +} + -+/* -+ * 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) -+ */ -+static int aspeed_ast2700_pcie_mmbi_init(struct platform_device *pdev) ++static long ++aspeed_mctp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ -+ 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; ++ struct mctp_client *client = file->private_data; ++ struct aspeed_mctp *priv = client->priv; ++ void __user *userbuf = (void __user *)arg; ++ int ret; ++ ++ switch (cmd) { ++ case ASPEED_MCTP_IOCTL_FILTER_EID: ++ ret = aspeed_mctp_filter_eid(priv, userbuf); ++ break; ++ ++ case ASPEED_MCTP_IOCTL_GET_BDF: ++ ret = aspeed_mctp_get_bdf(priv, userbuf); ++ break; + -+ /* 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 */ ++ case ASPEED_MCTP_IOCTL_GET_MEDIUM_ID: ++ ret = aspeed_mctp_get_medium_id(priv, userbuf); ++ break; + -+ 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); -+ } ++ case ASPEED_MCTP_IOCTL_GET_MTU: ++ ret = aspeed_mctp_get_mtu(priv, userbuf); ++ break; + -+ 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; -+ } ++ case ASPEED_MCTP_IOCTL_REGISTER_DEFAULT_HANDLER: ++ ret = aspeed_mctp_register_default_handler(client); ++ break; + -+ 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; -+ } ++ case ASPEED_MCTP_IOCTL_REGISTER_TYPE_HANDLER: ++ ret = aspeed_mctp_register_type_handler(client, userbuf); ++ break; + -+ 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; -+ } ++ case ASPEED_MCTP_IOCTL_UNREGISTER_TYPE_HANDLER: ++ ret = aspeed_mctp_unregister_type_handler(client, userbuf); ++ break; + -+ 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); -+ } else { -+ regmap_write(mmbi->device, 0x18, 0x0C0C0027); -+ regmap_write(mmbi->device, 0x78, ASPEED_SCU_INT_EN | ASPEED_SCU_DECODE_DEV); -+ } ++ case ASPEED_MCTP_IOCTL_GET_EID_INFO: ++ ret = aspeed_mctp_get_eid_info(priv, userbuf, ASPEED_MCTP_GENERIC_ADDR_FORMAT); ++ break; + -+ /* MSI */ -+ regmap_update_bits(mmbi->device, 0x74, GENMASK(7, 4), BIT(7) | (5 << 4)); ++ case ASPEED_MCTP_IOCTL_GET_EID_EXT_INFO: ++ ret = aspeed_mctp_get_eid_info(priv, userbuf, ASPEED_MCTP_EXTENDED_ADDR_FORMAT); ++ break; + -+ regmap_update_bits(mmbi->device, 0x70, BIT(25) | BIT(17) | BIT(9) | BIT(1), -+ BIT(25) | BIT(17) | BIT(9) | BIT(1)); ++ case ASPEED_MCTP_IOCTL_SET_EID_INFO: ++ ret = aspeed_mctp_set_eid_info(priv, userbuf, ASPEED_MCTP_GENERIC_ADDR_FORMAT); ++ break; + -+ /* 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); ++ case ASPEED_MCTP_IOCTL_SET_EID_EXT_INFO: ++ ret = aspeed_mctp_set_eid_info(priv, userbuf, ASPEED_MCTP_EXTENDED_ADDR_FORMAT); ++ break; + -+ /* 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); ++ case ASPEED_MCTP_IOCTL_SET_OWN_EID: ++ ret = aspeed_mctp_set_own_eid(priv, userbuf); ++ break; ++ ++ default: ++ dev_err(priv->dev, "Command not found\n"); ++ ret = -ENOTTY; + } + -+ /* 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); ++ return ret; ++} + -+ /* 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); ++static __poll_t aspeed_mctp_poll(struct file *file, ++ struct poll_table_struct *pt) ++{ ++ struct mctp_client *client = file->private_data; ++ __poll_t ret = 0; ++ struct aspeed_mctp *priv = client->priv; ++ struct mctp_channel *rx = &priv->rx; ++ u32 mctp_ctrl; ++ u32 mctp_int_sts; + -+ 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; ++ if (priv->miss_mctp_int) { ++ regmap_read(priv->map, ASPEED_MCTP_CTRL, &mctp_ctrl); ++ if (!(mctp_ctrl & RX_CMD_READY)) ++ rx->stopped = true; ++ /* Polling the RX_CMD_RECEIVE_INT to ensure rx_tasklet can find the data */ ++ regmap_read(priv->map, ASPEED_MCTP_INT_STS, &mctp_int_sts); ++ if (mctp_int_sts & RX_CMD_RECEIVE_INT) ++ regmap_write(priv->map, ASPEED_MCTP_INT_STS, ++ mctp_int_sts); + } + -+ INIT_WORK(&chan->work, aspeed_mmbi_work_func); ++ tasklet_hi_schedule(&priv->rx.tasklet); ++ poll_wait(file, &client->wait_queue, pt); + -+ return 0; -+} ++ if (!ptr_ring_full_bh(&client->tx_queue)) ++ ret |= EPOLLOUT; + -+struct aspeed_platform ast2700_platform = { -+ .mmbi_init = aspeed_ast2700_pcie_mmbi_init, -+}; ++ if (__ptr_ring_peek(&client->rx_queue)) ++ ret |= EPOLLIN; + -+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); ++ return ret; ++} + -+static int aspeed_pcie_mmbi_probe(struct platform_device *pdev) ++#ifdef CONFIG_MCTP_TRANSPORT_PCIE_VDM ++static int aspeed_mctp_pcie_vdm_op_send_pkt(struct device *dev, ++ u8 *data, size_t size) +{ -+ 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 mctp_pcie_packet *packet; ++ struct platform_device *pdev; ++ struct aspeed_mctp *priv; ++ int rc; + -+ md = of_device_get_match_data(dev); -+ if (!md) -+ return -ENODEV; ++ pdev = to_platform_device(dev); ++ priv = platform_get_drvdata(pdev); ++ // freed at aspeed-mctp tx tasklet or send failure ++ packet = aspeed_mctp_packet_alloc(GFP_KERNEL); + -+ mmbi = devm_kzalloc(&pdev->dev, sizeof(struct aspeed_pcie_mmbi), GFP_KERNEL); -+ if (!mmbi) ++ if (!packet) { ++ dev_err(priv->dev, "failed to alloc packet\n"); + 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); ++ memcpy((u8 *)&packet->data.hdr, data, PCIE_VDM_HDR_SIZE); ++ memcpy((u8 *)&packet->data.payload, data + PCIE_VDM_HDR_SIZE, size); ++ packet->size = (size + PCIE_VDM_HDR_SIZE); + -+ 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; ++ rc = aspeed_mctp_send_packet(priv->default_client, packet); ++ if (rc) { ++ dev_err(priv->dev, "failed to send packet\n"); ++ aspeed_mctp_packet_free(packet); ++ return rc; + } ++ return 0; ++} + -+ /* 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); -+ ret = mmbi->irq; -+ goto out_unmap; -+ } -+ 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; -+ } ++static u8 *aspeed_mctp_pcie_vdm_op_recv_pkt(struct device *dev) ++{ ++ struct platform_device *pdev; ++ struct aspeed_mctp *priv; ++ struct mctp_pcie_packet *rx_packet; + -+ chan = &mmbi->chan; -+ memset(chan, 0, sizeof(struct aspeed_mmbi_channel)); ++ pdev = to_platform_device(dev); ++ priv = platform_get_drvdata(pdev); ++ rx_packet = aspeed_mctp_receive_packet(priv->default_client, 0); + -+ 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; ++ if (IS_ERR(rx_packet)) { ++ if (PTR_ERR(rx_packet) == -ETIME) { ++ dev_dbg(priv->dev, "no packet received\n"); ++ } else { ++ dev_err(priv->dev, "failed to receive packet: %ld\n", ++ PTR_ERR(rx_packet)); ++ } ++ return (u8 *)rx_packet; + } ++ return (u8 *)&rx_packet->data; ++} + -+ ret = mmbi->platform->mmbi_init(pdev); -+ if (ret) { -+ dev_err(dev, "Initialize pcie mmbi failed\n"); -+ goto out_irq; -+ } ++static void aspeed_mctp_pcie_vdm_op_uninit(struct device *dev) ++{ ++ struct platform_device *pdev; ++ struct aspeed_mctp *priv; + -+ dev_info(dev, "ASPEED PCIe MMBI Dev %d: driver successfully loaded.\n", mmbi->id); ++ pdev = to_platform_device(dev); ++ priv = platform_get_drvdata(pdev); + -+ 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 pcie mmbi: driver init failed (ret=%d)!\n", ret); -+ return ret; ++ aspeed_mctp_flush_all_tx_queues(priv); ++ aspeed_mctp_flush_rx_queue(priv->default_client); ++ aspeed_mctp_delete_client(priv->default_client); +} + -+static void aspeed_pcie_mmbi_remove(struct platform_device *pdev) -+{ -+ struct aspeed_pcie_mmbi *mmbi = platform_get_drvdata(pdev); ++static const struct mctp_pcie_vdm_ops aspeed_mctp_pcie_vdm_ops = { ++ .send_packet = aspeed_mctp_pcie_vdm_op_send_pkt, ++ .recv_packet = aspeed_mctp_pcie_vdm_op_recv_pkt, ++ .free_packet = aspeed_mctp_packet_free, ++ .uninit = aspeed_mctp_pcie_vdm_op_uninit, ++}; + -+ 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); -+} ++#endif + -+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, -+ }, ++static const struct file_operations aspeed_mctp_fops = { ++ .owner = THIS_MODULE, ++ .open = aspeed_mctp_open, ++ .release = aspeed_mctp_release, ++ .read = aspeed_mctp_read, ++ .write = aspeed_mctp_write, ++ .unlocked_ioctl = aspeed_mctp_ioctl, ++ .poll = aspeed_mctp_poll, +}; + -+module_platform_driver(aspeed_pcie_mmbi_driver); ++static const struct regmap_config aspeed_mctp_regmap_cfg = { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .max_register = ASPEED_G7_MCTP_PCIE_BDF, ++}; + -+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 2026-04-08 18:03:48.311705302 +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__ ++struct device_type aspeed_mctp_type = { ++ .name = "aspeed-mctp", ++}; + -+#define MMBI_SIGNATURE "#MMBI$" ++static void aspeed_mctp_send_pcie_uevent(struct kobject *kobj, bool ready) ++{ ++ char buf[32]; ++ char *envp[2]; + -+//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 ++ snprintf(buf, sizeof(buf), ASPEED_MCTP_READY "=%d", ready ? 1 : 0); ++ envp[0] = buf; ++ envp[1] = NULL; + -+#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) ++ kobject_uevent_env(kobj, KOBJ_CHANGE, envp); ++} + -+#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) ++static void aspeed_mctp_irq_enable(struct aspeed_mctp *priv) ++{ ++ u32 enable = TX_CMD_SENT_INT | TX_CMD_WRONG_INT | ++ RX_CMD_RECEIVE_INT | RX_CMD_NO_MORE_INT; + -+#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) ++ regmap_write(priv->map, ASPEED_MCTP_INT_EN, enable); ++} + -+#define GET_HOST_READY_BIT(x) (MMBI_HRWS1(x) & 0x01) -+#define GET_BMC_READY_BIT(x) (MMBI_HROS1(x) & 0x01) ++static void aspeed_mctp_irq_disable(struct aspeed_mctp *priv) ++{ ++ regmap_write(priv->map, ASPEED_MCTP_INT_EN, 0); ++} + -+typedef u8 protocol_type; ++static void aspeed_mctp_pcie_setup(struct aspeed_mctp *priv) ++{ ++ int ret; ++ u8 tx_max_payload_size; ++ u8 rx_max_payload_size; ++ struct kobject *kobj = &priv->mctp_miscdev.this_device->kobj; + -+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, -+}; ++ ret = _get_bdf(priv); + -+struct mmbi_header { -+ u32 pkt_pad : 2; -+ u32 pkt_len : 22; -+ u32 pkt_type : 4; -+ u32 reserved : 4; -+}; ++ if (ret >= 0) { ++ cancel_delayed_work(&priv->pcie.rst_dwork); ++ if (priv->match_data->need_address_mapping) ++ regmap_update_bits(priv->map, ASPEED_MCTP_EID, ++ MEMORY_SPACE_MAPPING, BIT(31)); + -+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 */ -+}; ++ /* Only set TX MPS since HW will parse RX packet to decide how many bytes to receive ++ * based on the length field in PCIe VDM header. ++ */ ++ if (priv->match_data->dma_need_64bits_width) { ++ tx_max_payload_size = ++ FIELD_GET(TX_MAX_PAYLOAD_SIZE_MASK, ++ ilog2(ASPEED_MCTP_MTU >> 6)); ++ } else { ++ /* ++ * In ast2600, tx som and eom will not match expected result. ++ * e.g. When Maximum Transmit Unit (MTU) set to 64 byte, and then transfer ++ * size set between 61 ~ 124 (MTU-3 ~ 2*MTU-4), the engine will set all ++ * packet vdm header eom to 1, no matter what it setted. To fix that ++ * issue, the driver set MTU to next level(e.g. 64 to 128). ++ */ ++ tx_max_payload_size = ++ FIELD_GET(TX_MAX_PAYLOAD_SIZE_MASK, ++ fls(ASPEED_MCTP_MTU >> 6)); ++ } + -+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 */ -+}; ++ regmap_update_bits(priv->map, ASPEED_MCTP_ENGINE_CTRL, ++ TX_MAX_PAYLOAD_SIZE_MASK | RX_MAX_PAYLOAD_SIZE_MASK, ++ (rx_max_payload_size << RX_MAX_PAYLOAD_SIZE_SHIFT) | tx_max_payload_size); + -+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; ++ aspeed_mctp_flush_all_tx_queues(priv); ++ if (!priv->miss_mctp_int) { ++ aspeed_mctp_irq_enable(priv); ++ } else { ++ if (priv->rx_det_period_us) ++ schedule_delayed_work(&priv->rx_det_dwork, ++ usecs_to_jiffies(priv->rx_det_period_us)); ++ } ++ aspeed_mctp_rx_trigger(&priv->rx); ++ aspeed_mctp_send_pcie_uevent(kobj, true); ++ } else { ++ schedule_delayed_work(&priv->pcie.rst_dwork, ++ msecs_to_jiffies(1000)); ++ } ++} + -+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; ++static void aspeed_mctp_reset_work(struct work_struct *work) ++{ ++ struct aspeed_mctp *priv = container_of(work, typeof(*priv), ++ pcie.rst_dwork.work); ++ struct kobject *kobj = &priv->mctp_miscdev.this_device->kobj; + -+struct aspeed_pcie_mmbi; ++ if (priv->pcie.need_uevent) { ++ aspeed_mctp_send_pcie_uevent(kobj, false); ++ priv->pcie.need_uevent = false; ++ } ++ ++ aspeed_mctp_pcie_setup(priv); ++} ++ ++static void aspeed_mctp_rx_detect_work(struct work_struct *work) ++{ ++ struct aspeed_mctp *priv = ++ container_of(work, typeof(*priv), rx_det_dwork.work); ++ ++ tasklet_hi_schedule(&priv->rx.tasklet); ++ schedule_delayed_work(&priv->rx_det_dwork, ++ usecs_to_jiffies(priv->rx_det_period_us)); ++} + -+#define MCTP_MMBI_MTU 65536 -+#define MCTP_MMBI_MTU_MIN 68 /* base mtu (64) + mctp header */ -+#define MCTP_MMBI_MTU_MAX 65536 ++static void aspeed_mctp_channels_init(struct aspeed_mctp *priv) ++{ ++ aspeed_mctp_rx_chan_init(&priv->rx); ++ aspeed_mctp_tx_chan_init(&priv->tx); ++} + -+struct aspeed_mmbi_mctp { -+ struct aspeed_pcie_mmbi *mmbi; -+ struct net_device *ndev; -+}; ++static irqreturn_t aspeed_mctp_irq_handler(int irq, void *arg) ++{ ++ struct aspeed_mctp *priv = arg; ++ u32 handled = 0; ++ u32 status; + -+struct aspeed_mmbi_channel { -+ struct aspeed_pcie_mmbi *mmbi; -+ struct device *dev; ++ regmap_read(priv->map, ASPEED_MCTP_INT_STS, &status); ++ regmap_write(priv->map, ASPEED_MCTP_INT_STS, status); + -+ 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; ++ if (status & TX_CMD_SENT_INT) { ++ tasklet_hi_schedule(&priv->tx.tasklet); ++ if (!priv->match_data->fifo_auto_surround) ++ priv->tx.rd_ptr = (priv->tx.rd_ptr + 1) % TX_PACKET_COUNT; ++ handled |= TX_CMD_SENT_INT; ++ } + -+ bool bmc_int_en; -+ u8 bmc_int_value; -+ u32 bmc_int_location; -+ u8 __iomem *bmc_int_vmem; ++ if (status & TX_CMD_WRONG_INT) { ++ /* TODO: print the actual command */ ++ dev_warn(priv->dev, "TX wrong"); + -+ bool host_int_en; -+ u8 host_int_location; -+ u8 host_int_value; ++ handled |= TX_CMD_WRONG_INT; ++ } + -+ enum mmbi_state state; ++ if (status & RX_CMD_RECEIVE_INT) { ++ tasklet_hi_schedule(&priv->rx.tasklet); + -+ /* MCTP */ -+ struct net_device *ndev; ++ handled |= RX_CMD_RECEIVE_INT; ++ } + -+ struct work_struct work; -+}; ++ if (status & RX_CMD_NO_MORE_INT) { ++ dev_dbg(priv->dev, "RX full"); ++ priv->rx.stopped = true; ++ tasklet_hi_schedule(&priv->rx.tasklet); + -+#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 2026-04-08 18:03:48.311705302 +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 2026-04-08 18:03:48.311705302 +0000 -@@ -0,0 +1,275 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+// Copyright (C) ASPEED Technology Inc. ++ handled |= RX_CMD_NO_MORE_INT; ++ } + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++ if (!handled) ++ return IRQ_NONE; + -+#define SSP_FILE_NAME "ast2600_ssp.bin" -+#define AST2600_CVIC_TRIGGER 0x28 -+#define AST2600_CVIC_PENDING_STATUS 0x18 -+#define AST2600_CVIC_PENDING_CLEAR 0x1C ++ return IRQ_HANDLED; ++} + -+#define SSP_CTRL_REG 0xa00 -+#define SSP_CTRL_RESET_ASSERT BIT(1) -+#define SSP_CTRL_EN BIT(0) ++static irqreturn_t aspeed_mctp_pcie_rst_irq_handler(int irq, void *arg) ++{ ++ struct aspeed_mctp *priv = arg; + -+#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) ++ aspeed_mctp_channels_init(priv); + -+#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) ++ priv->pcie.need_uevent = true; ++ priv->eid = 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; -+}; ++ schedule_delayed_work(&priv->pcie.rst_dwork, 0); + -+static int ast_ssp_open(struct inode *inode, struct file *file) -+{ -+ return 0; ++ return IRQ_HANDLED; +} + -+static int ast_ssp_release(struct inode *inode, struct file *file) ++static void aspeed_mctp_drv_init(struct aspeed_mctp *priv) +{ -+ return 0; ++ INIT_LIST_HEAD(&priv->clients); ++ INIT_LIST_HEAD(&priv->mctp_type_handlers); ++ INIT_LIST_HEAD(&priv->endpoints); ++ ++ spin_lock_init(&priv->clients_lock); ++ mutex_init(&priv->endpoints_lock); ++ ++ INIT_DELAYED_WORK(&priv->pcie.rst_dwork, aspeed_mctp_reset_work); ++ ++ tasklet_init(&priv->tx.tasklet, aspeed_mctp_tx_tasklet, ++ (unsigned long)&priv->tx); ++ tasklet_init(&priv->rx.tasklet, aspeed_mctp_rx_tasklet, ++ (unsigned long)&priv->rx); +} + -+static const struct file_operations ast_ssp_fops = { -+ .owner = THIS_MODULE, -+ .open = ast_ssp_open, -+ .release = ast_ssp_release, -+ .llseek = noop_llseek, -+}; ++static void aspeed_mctp_drv_fini(struct aspeed_mctp *priv) ++{ ++ aspeed_mctp_eid_info_list_remove(&priv->endpoints); ++ tasklet_disable(&priv->tx.tasklet); ++ tasklet_kill(&priv->tx.tasklet); ++ tasklet_disable(&priv->rx.tasklet); ++ tasklet_kill(&priv->rx.tasklet); + -+struct miscdevice ast_ssp_misc = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = "ast-ssp", -+ .fops = &ast_ssp_fops, -+}; ++ cancel_delayed_work_sync(&priv->pcie.rst_dwork); ++ if (priv->miss_mctp_int) ++ cancel_delayed_work_sync(&priv->rx_det_dwork); ++} + -+static irqreturn_t ast2600_ssp_interrupt(int irq, void *dev_id) ++static int aspeed_mctp_resources_init(struct aspeed_mctp *priv) +{ -+ 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; ++ struct platform_device *pdev = to_platform_device(priv->dev); ++ void __iomem *regs; + -+ dev_info(priv->dev, "isr %x\n", isr); -+ writel(isr, priv->cvic + AST2600_CVIC_PENDING_CLEAR); ++ regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(regs)) { ++ dev_err(priv->dev, "Failed to get regmap!\n"); ++ return PTR_ERR(regs); ++ } + -+ dev_info(priv->dev, "[CA7] rx addr:%08x, tx addr:%08x\n", -+ (u32)ssp_shared_mem_rx, (u32)ssp_shared_mem_tx); ++ priv->map = devm_regmap_init_mmio(priv->dev, regs, ++ &aspeed_mctp_regmap_cfg); ++ if (IS_ERR(priv->map)) ++ return PTR_ERR(priv->map); + -+ /* 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; ++ priv->reset = ++ priv->rc_f ? ++ devm_reset_control_get_by_index(priv->dev, 0) : ++ devm_reset_control_get_shared_by_index(priv->dev, 0); ++ if (IS_ERR(priv->reset)) { ++ dev_err(priv->dev, "Failed to get reset!\n"); ++ 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); + } + } ++ priv->pcie.map = ++ syscon_regmap_lookup_by_phandle(priv->dev->of_node, ++ "aspeed,pcieh"); ++ if (IS_ERR(priv->pcie.map)) { ++ dev_err(priv->dev, "Failed to find PCIe Host regmap!\n"); ++ return PTR_ERR(priv->pcie.map); ++ } + -+ return IRQ_HANDLED; ++ platform_set_drvdata(pdev, priv); ++ ++ return 0; +} + -+static int ast_ssp_probe(struct platform_device *pdev) ++static void aspeed_release_rmem(void *d) +{ -+ 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; ++ of_reserved_mem_device_release(d); ++} + -+ priv = kzalloc(sizeof(*priv), GFP_KERNEL); -+ if (!priv) { -+ ret = -ENOMEM; -+ goto finish; -+ } ++static int aspeed_mctp_dma_init(struct aspeed_mctp *priv) ++{ ++ struct mctp_channel *tx = &priv->tx; ++ struct mctp_channel *rx = &priv->rx; ++ size_t alloc_size; ++ int ret = -ENOMEM; + -+ 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); ++ BUILD_BUG_ON(TX_PACKET_COUNT >= TX_MAX_PACKET_COUNT); ++ BUILD_BUG_ON(RX_PACKET_COUNT >= RX_MAX_PACKET_COUNT); + -+ ret = misc_register(&ast_ssp_misc); ++ ret = of_reserved_mem_device_init(priv->dev); + if (ret) { -+ pr_err("can't misc_register :(\n"); -+ ret = -EIO; -+ goto finish; ++ dev_err(priv->dev, "device does not have specific DMA pool: %d\n", ++ ret); ++ return ret; + } -+ dev_set_drvdata(ast_ssp_misc.this_device, pdev); + -+ ret = of_reserved_mem_device_init(&pdev->dev); ++ ret = devm_add_action_or_reset(priv->dev, aspeed_release_rmem, ++ priv->dev); ++ if (ret) ++ return ret; ++ ++ ret = dma_set_mask_and_coherent(priv->dev, DMA_BIT_MASK(64)); + if (ret) { -+ dev_err(priv->dev, -+ "failed to initialize reserved mem: %d\n", ret); -+ ret = -ENOMEM; -+ goto finish; ++ dev_err(priv->dev, "cannot set 64-bits DMA mask\n"); ++ return ret; + } + -+ 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; -+ } ++ 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); + -+ 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 (!rx->data.vaddr) ++ return -ENOMEM; + -+ 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; -+ } ++ alloc_size = PAGE_ALIGN(priv->rx_packet_count * priv->match_data->rx_cmd_size); ++ rx->cmd.vaddr = dma_alloc_coherent(priv->dev, alloc_size, &rx->cmd.dma_handle, GFP_KERNEL); + -+ 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 (!rx->cmd.vaddr) ++ goto out_rx_cmd; + -+ 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; -+ } ++ alloc_size = PAGE_ALIGN(TX_PACKET_COUNT * priv->match_data->packet_unit_size); ++ tx->data.vaddr = ++ dma_alloc_coherent(priv->dev, alloc_size, &tx->data.dma_handle, GFP_KERNEL); + -+ memcpy(priv->ssp_mem_vir_addr, (void *)firmware->data, firmware->size); -+ release_firmware(firmware); ++ if (!tx->data.vaddr) ++ goto out_tx_data; ++ alloc_size = PAGE_ALIGN(TX_PACKET_COUNT * priv->match_data->tx_cmd_size); ++ tx->cmd.vaddr = dma_alloc_coherent(priv->dev, alloc_size, &tx->cmd.dma_handle, GFP_KERNEL); + -+ np = of_parse_phandle(mnode, "aspeed,cvic", 0); -+ if (!np) { -+ dev_err(priv->dev, "can't find CVIC\n"); -+ ret = -EINVAL; -+ goto finish; -+ } ++ if (!tx->cmd.vaddr) ++ goto out_tx_cmd; + -+ 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; -+ } ++ return 0; ++out_tx_cmd: ++ alloc_size = PAGE_ALIGN(TX_PACKET_COUNT * ++ priv->match_data->packet_unit_size); ++ dma_free_coherent(priv->dev, alloc_size, tx->data.vaddr, ++ tx->data.dma_handle); + -+ 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++; ++out_tx_data: ++ alloc_size = PAGE_ALIGN(priv->rx_packet_count * ++ priv->match_data->rx_cmd_size); ++ dma_free_coherent(priv->dev, alloc_size, rx->cmd.vaddr, ++ rx->cmd.dma_handle); ++ ++out_rx_cmd: ++ alloc_size = PAGE_ALIGN(priv->rx_packet_count * ++ priv->match_data->packet_unit_size); ++ dma_free_coherent(priv->dev, alloc_size, rx->data.vaddr, ++ rx->data.dma_handle); ++ ++ return -ENOMEM; ++} ++ ++static void aspeed_mctp_dma_fini(struct aspeed_mctp *priv) ++{ ++ struct mctp_channel *tx = &priv->tx; ++ struct mctp_channel *rx = &priv->rx; ++ size_t free_size; ++ ++ free_size = PAGE_ALIGN(TX_PACKET_COUNT * priv->match_data->tx_cmd_size); ++ dma_free_coherent(priv->dev, free_size, tx->cmd.vaddr, ++ tx->cmd.dma_handle); ++ ++ free_size = PAGE_ALIGN(priv->rx_packet_count * ++ priv->match_data->rx_cmd_size); ++ dma_free_coherent(priv->dev, free_size, rx->cmd.vaddr, ++ rx->cmd.dma_handle); ++ ++ free_size = PAGE_ALIGN(TX_PACKET_COUNT * ++ priv->match_data->packet_unit_size); ++ dma_free_coherent(priv->dev, free_size, tx->data.vaddr, ++ tx->data.dma_handle); ++ ++ free_size = PAGE_ALIGN(priv->rx_packet_count * ++ priv->match_data->packet_unit_size); ++ dma_free_coherent(priv->dev, free_size, rx->data.vaddr, ++ rx->data.dma_handle); ++} ++ ++static int aspeed_mctp_irq_init(struct aspeed_mctp *priv) ++{ ++ struct platform_device *pdev = to_platform_device(priv->dev); ++ int irq, ret; ++ ++ irq = platform_get_irq_byname_optional(pdev, "mctp"); ++ if (irq < 0) { ++ /* mctp irq is option */ ++ priv->miss_mctp_int = 1; ++ INIT_DELAYED_WORK(&priv->rx_det_dwork, aspeed_mctp_rx_detect_work); ++ } else { ++ ret = devm_request_irq(priv->dev, irq, aspeed_mctp_irq_handler, ++ IRQF_SHARED, dev_name(&pdev->dev), priv); ++ if (ret) ++ return ret; ++ aspeed_mctp_irq_enable(priv); + } -+ priv->n_irq = i; -+ dev_info(priv->dev, "%d ISRs registered\n", priv->n_irq); ++ irq = platform_get_irq_byname(pdev, "pcie"); ++ if (!irq) ++ return -ENODEV; + -+ 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); ++ ret = devm_request_irq(priv->dev, irq, aspeed_mctp_pcie_rst_irq_handler, ++ IRQF_SHARED, dev_name(&pdev->dev), priv); ++ if (ret) ++ return ret; + -+ regmap_write(priv->scu, SSP_CACHE_RANGE_REG, SSP_CACHE_1ST_16MB_ENABLE); ++ return 0; ++} + -+ 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); ++static int aspeed_mctp_hw_reset(struct aspeed_mctp *priv) ++{ ++ int ret = 0; ++ ++ ret = reset_control_deassert(priv->reset); ++ if (ret) { ++ dev_warn(priv->dev, "Failed to deassert reset\n"); ++ return ret; ++ } ++ ++ if (priv->rc_f) { ++ ret = reset_control_deassert(priv->reset_dma); ++ if (ret) { ++ dev_warn(priv->dev, "Failed to deassert ep reset\n"); ++ return ret; ++ } ++ } ++ ++ if (priv->match_data->dma_need_64bits_width) ++ ret = pcie_vdm_enable(priv->dev); + -+ dev_info(priv->dev, "Init successful\n"); -+ ret = 0; -+finish: + return ret; +} + -+static void ast_ssp_remove(struct platform_device *pdev) ++static int aspeed_mctp_probe(struct platform_device *pdev) +{ -+ struct ast2600_ssp *priv = platform_get_drvdata(pdev); -+ int i; ++ struct aspeed_mctp *priv; ++ int ret, id; ++ const char *name; + -+ 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); ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ priv->dev = &pdev->dev; ++ priv->rc_f = ++ of_find_property(priv->dev->of_node, "pcie_rc", NULL) ? 1 : 0; ++ priv->match_data = of_device_get_match_data(priv->dev); ++ ++ ret = device_property_read_u32(priv->dev, "aspeed,rx-packet-count", ++ &priv->rx_packet_count); ++ if (ret) { ++ priv->rx_packet_count = RX_PACKET_COUNT; ++ } else if (priv->rx_packet_count % 4 || ++ priv->rx_packet_count >= RX_MAX_PACKET_COUNT) { ++ dev_err(priv->dev, ++ "The aspeed,rx-packet-count:%d should be 4-aligned and less than %ld", ++ priv->rx_packet_count, RX_MAX_PACKET_COUNT); ++ ret = -EINVAL; ++ goto out; ++ } + -+ kfree(priv); ++ ret = device_property_read_u32(priv->dev, "aspeed,rx-ring-count", ++ &priv->rx_ring_count); ++ if (ret) ++ priv->rx_ring_count = RX_RING_COUNT; + -+ misc_deregister((struct miscdevice *)&ast_ssp_misc); -+} ++ ret = device_property_read_u32(priv->dev, "aspeed,tx-ring-count", ++ &priv->tx_ring_count); ++ if (ret) ++ priv->tx_ring_count = TX_RING_COUNT; + -+static const struct of_device_id of_ast_ssp_match_table[] = { -+ { .compatible = "aspeed,ast2600-ssp", }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, of_ast_ssp_match_table); ++ ret = device_property_read_u32(priv->dev, "aspeed,rx-det-period-us", ++ &priv->rx_det_period_us); ++ if (ret) ++ priv->rx_det_period_us = 1000; + -+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, -+ }, -+}; ++ aspeed_mctp_drv_init(priv); + -+module_platform_driver(ast_ssp_driver); ++ ret = aspeed_mctp_resources_init(priv); ++ if (ret) { ++ dev_err(priv->dev, "Failed to init resources\n"); ++ goto out_drv; ++ } + -+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 2026-04-08 18:03:48.311705302 +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, -+ }, -+}; ++#ifdef CONFIG_MCTP_TRANSPORT_PCIE_VDM ++ struct net_device *ndev; ++ struct mctp_client *client; + -+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, -+ }, -+}; ++ /** use priv's default client to send/receive mctp packets */ ++ client = aspeed_mctp_create_client(priv); ++ aspeed_mctp_register_default_handler(client); + -+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, -+ }, -+}; ++ 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 + -+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, -+ }, -+}; ++ ret = aspeed_mctp_dma_init(priv); ++ if (ret) { ++ dev_err(priv->dev, "Failed to init DMA\n"); ++ goto out_drv; ++ } + -+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, -+ }, -+}; ++ ret = aspeed_mctp_hw_reset(priv); ++ if (ret) ++ goto out_drv; + -+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, -+ }, -+}; ++ aspeed_mctp_channels_init(priv); + -+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, -+ }, -+}; ++ 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; + -+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, -+ }, -+}; ++ 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_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, -+ }, -+}; ++ 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_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, -+ }, -+}; ++ return 0; + -+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, -+}; ++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 const struct attribute_group ast2700n0_uart_routing_attr_group = { -+ .attrs = ast2700n0_uart_routing_attrs, -+}; ++static void aspeed_mctp_remove(struct platform_device *pdev) ++{ ++ struct aspeed_mctp *priv = platform_get_drvdata(pdev); + -+/* 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, -+ }, -+}; ++#ifdef CONFIG_MCTP_TRANSPORT_PCIE_VDM ++ mctp_pcie_vdm_remove_dev(priv->ndev); ++#endif + -+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, -+ }, -+}; ++ platform_device_unregister(priv->peci_mctp); + -+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, -+ }, -+}; ++ misc_deregister(&priv->mctp_miscdev); + -+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, -+ }, -+}; ++ aspeed_mctp_irq_disable(priv); + -+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, -+ }, -+}; ++ aspeed_mctp_dma_fini(priv); + -+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, -+ }, -+}; ++ aspeed_mctp_drv_fini(priv); ++} + -+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 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_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 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_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, -+ }, ++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_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 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 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, ++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 const struct attribute_group ast2700n1_uart_routing_attr_group = { -+ .attrs = ast2700n1_uart_routing_attrs, ++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 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, ++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-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_uart_routing_probe, -- .remove_new = aspeed_uart_routing_remove, -+ .remove = aspeed_uart_routing_remove, + .probe = aspeed_p2a_ctrl_probe, +- .remove_new = aspeed_p2a_ctrl_remove, ++ .remove = aspeed_p2a_ctrl_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 2026-04-08 18:03:48.311705302 +0000 -@@ -0,0 +1,424 @@ + 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 @@ +// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright 2020 Aspeed Technology Inc. -+ */ -+#include -+#include -+#include -+#include -+#include ++// Copyright (C) ASPEED Technology Inc. ++ ++#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 -+ -+#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) + -+#define UDMA_MAX_CHANNEL 16 -+#define UDMA_TMOUT 0x200 ++#include ++#include + -+enum aspeed_udma_bufsz_code { -+ UDMA_BUFSZ_CODE_1KB, -+ UDMA_BUFSZ_CODE_4KB, -+ UDMA_BUFSZ_CODE_16KB, -+ UDMA_BUFSZ_CODE_64KB, -+}; ++#include ++#include ++#include ++#include ++#include ++#include + -+struct aspeed_udma_chan { -+ dma_addr_t dma_addr; ++#include ++#include ++#include ++#include ++#include + -+ u32 rb_sz; ++#include "aspeed-pcie-mmbi.h" + -+ aspeed_udma_cb_t cb; -+ void *cb_arg; ++/* 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 + -+ bool dis_tmout; ++/* 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); +}; + -+struct aspeed_udma { ++struct aspeed_pcie_mmbi { + struct device *dev; -+ u8 __iomem *regs; ++ struct regmap *device; ++ struct regmap *e2m; + int irq; -+ struct aspeed_udma_chan tx_chs[UDMA_MAX_CHANNEL]; -+ struct aspeed_udma_chan rx_chs[UDMA_MAX_CHANNEL]; -+ spinlock_t lock; ++ 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 udma[1]; ++static void mmbi_desc_init(struct aspeed_mmbi_channel *chan); + -+static int aspeed_udma_get_bufsz_code(u32 buf_sz) ++static u8 mmbi_get_bmc_up(struct aspeed_mmbi_channel *chan) +{ -+ 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; -+ } ++ struct host_ros hros; + -+ return -1; ++ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); ++ ++ return hros.b_up; +} + -+static u32 aspeed_udma_get_tx_rptr(u32 ch_no) ++static u8 mmbi_get_bmc_rdy(struct aspeed_mmbi_channel *chan) +{ -+ return readl(udma->regs + UDMA_CHX_TX_RD_PTR(ch_no)); ++ struct host_ros hros; ++ ++ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); ++ ++ return hros.b_rdy; +} + -+static u32 aspeed_udma_get_rx_wptr(u32 ch_no) ++static u8 mmbi_get_bmc_rst(struct aspeed_mmbi_channel *chan) +{ -+ return readl(udma->regs + UDMA_CHX_RX_WR_PTR(ch_no)); ++ struct host_ros hros; ++ ++ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); ++ ++ return hros.b_rst; +} + -+static void aspeed_udma_set_ptr(u32 ch_no, u32 ptr, bool is_tx) ++static u8 mmbi_get_host_rst(struct aspeed_mmbi_channel *chan) +{ -+ writel(ptr, udma->regs + -+ ((is_tx) ? UDMA_CHX_TX_WR_PTR(ch_no) : UDMA_CHX_RX_RD_PTR(ch_no))); ++ struct host_rws hrws; ++ ++ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); ++ ++ return hrws.h_rst; +} + -+void aspeed_udma_set_tx_wptr(u32 ch_no, u32 wptr) ++static u8 mmbi_get_host_rdy(struct aspeed_mmbi_channel *chan) +{ -+ aspeed_udma_set_ptr(ch_no, wptr, true); ++ struct host_rws hrws; ++ ++ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); ++ ++ return hrws.h_rdy; +} -+EXPORT_SYMBOL(aspeed_udma_set_tx_wptr); + -+void aspeed_udma_set_rx_rptr(u32 ch_no, u32 rptr) ++static u8 mmbi_get_host_up(struct aspeed_mmbi_channel *chan) +{ -+ aspeed_udma_set_ptr(ch_no, rptr, false); ++ struct host_rws hrws; ++ ++ memcpy_fromio(&hrws, chan->hrws_vmem, sizeof(hrws)); ++ ++ return hrws.h_up; +} -+EXPORT_SYMBOL(aspeed_udma_set_rx_rptr); + -+static int aspeed_udma_free_chan(u32 ch_no, bool is_tx) ++static void mmbi_set_bmc_rst(struct aspeed_mmbi_channel *chan, bool set) +{ -+ u32 reg; -+ unsigned long flags; ++ struct host_ros hros; + -+ if (ch_no > UDMA_MAX_CHANNEL) -+ return -EINVAL; ++ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); ++ hros.b_rst = set; ++ memcpy_toio(chan->hros_vmem, &hros, sizeof(hros)); ++} + -+ spin_lock_irqsave(&udma->lock, flags); ++static void mmbi_set_bmc_rdy(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_rdy = 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 mmbi_set_bmc_up(struct aspeed_mmbi_channel *chan, bool set) ++{ ++ struct host_ros hros; + -+ spin_unlock_irqrestore(&udma->lock, flags); ++ memcpy_fromio(&hros, chan->hros_vmem, sizeof(hros)); ++ hros.b_up = set; ++ memcpy_toio(chan->hros_vmem, &hros, sizeof(hros)); ++} + -+ return 0; ++static void raise_b2h_interrupt(struct aspeed_mmbi_channel *chan) ++{ ++ if (!chan->host_int_en) ++ return; ++ ++ regmap_write(chan->mmbi->e2m, ASPEED_E2M_EVENT_SET, BIT(chan->mmbi->e2m_h2b_int)); +} + -+int aspeed_udma_free_tx_chan(u32 ch_no) ++static void mmbi_clear_hros(struct aspeed_mmbi_channel *chan) +{ -+ return aspeed_udma_free_chan(ch_no, true); ++ memset_io(chan->hros_vmem, 0, sizeof(struct host_ros)); +} -+EXPORT_SYMBOL(aspeed_udma_free_tx_chan); + -+int aspeed_udma_free_rx_chan(u32 ch_no) ++static void mmbi_clear_hrws(struct aspeed_mmbi_channel *chan) +{ -+ return aspeed_udma_free_chan(ch_no, false); ++ memset_io(chan->hrws_vmem, 0, sizeof(struct host_rws)); +} -+EXPORT_SYMBOL(aspeed_udma_free_rx_chan); + -+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) ++static void get_b2h_avail_buf_len(struct aspeed_mmbi_channel *chan, ssize_t *avail_buf_len) +{ -+ int retval = 0; -+ int rbsz_code; ++ struct device *dev = chan->dev; ++ u32 b2h_rp, b2h_wp; + -+ u32 reg; -+ unsigned long flags; -+ struct aspeed_udma_chan *ch; ++ 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); + -+ if (ch_no > UDMA_MAX_CHANNEL) { -+ retval = -EINVAL; -+ goto out; -+ } ++ if (b2h_wp >= b2h_rp) ++ *avail_buf_len = chan->b2h_cb_size - b2h_wp + b2h_rp; ++ else ++ *avail_buf_len = b2h_rp - b2h_wp; ++} + -+ rbsz_code = aspeed_udma_get_bufsz_code(rb_sz); -+ if (rbsz_code < 0) { -+ retval = -EINVAL; -+ goto out; -+ } ++static u8 mmbi_get_state(struct aspeed_mmbi_channel *chan) ++{ ++ u8 state = 0; + -+ spin_lock_irqsave(&udma->lock, flags); ++ 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); + -+ if (is_tx) { -+ reg = readl(udma->regs + UDMA_TX_DMA_INT_EN); -+ if (reg & (0x1 << ch_no)) { -+ retval = -EBUSY; -+ goto unlock_n_out; -+ } ++ return state; ++} + -+ reg |= (0x1 << ch_no); -+ writel(reg, udma->regs + UDMA_TX_DMA_INT_EN); ++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; + -+ 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)); ++ 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); + -+ 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; -+ } ++ 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 |= (0x1 << ch_no); -+ writel(reg, udma->regs + UDMA_RX_DMA_INT_EN); ++ if (*unread_data_len < sizeof(struct mmbi_header)) { ++ dev_dbg(dev, "No data to read(%d - %d)\n", h2b_wp, h2b_rp); ++ return -EAGAIN; ++ } + -+ 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)); ++ dev_dbg(dev, "READ MMBI header from: 0x%lx\n", ++ (ssize_t)(chan->h2b_cb_vmem + h2b_rp)); + -+ writel(addr, udma->regs + UDMA_CHX_RX_BUF_ADDR(ch_no)); ++ /* 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; ++ ++ 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); + } + -+ 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; ++ *data_length = (header.pkt_len << 2) - sizeof(header) - header.pkt_pad; ++ *padding = header.pkt_pad; ++ *type = header.pkt_type; + -+unlock_n_out: -+ spin_unlock_irqrestore(&udma->lock, flags); -+out: + return 0; +} + -+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, 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, u32 rb_sz, -+ aspeed_udma_cb_t cb, void *id, bool dis_tmout) -+{ -+ return aspeed_udma_request_chan(ch_no, addr, rb_sz, cb, id, -+ dis_tmout, false); -+} -+EXPORT_SYMBOL(aspeed_udma_request_rx_chan); -+ -+static void aspeed_udma_chan_ctrl(u32 ch_no, u32 op, bool is_tx) ++static int mmbi_state_check(struct aspeed_mmbi_channel *chan) +{ -+ 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; -+ -+ spin_lock_irqsave(&udma->lock, flags); -+ -+ reg_en = readl(udma->regs + reg_en_off); -+ reg_rst = readl(udma->regs + reg_rst_off); ++ 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 (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); ++ 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); + -+ reg_rst |= (0x1 << ch_no); -+ writel(reg_rst, udma->regs + reg_rst_off); ++ 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); + -+ udelay(100); ++ 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); + -+ reg_rst &= ~(0x1 << ch_no); -+ writel(reg_rst, udma->regs + reg_rst_off); -+ break; ++ dev_dbg(dev, "Change state to INIT_COMPLETED to HOST"); ++ raise_b2h_interrupt(chan); + default: + break; + } + -+ spin_unlock_irqrestore(&udma->lock, flags); -+} -+ -+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); -+ -+void aspeed_udma_rx_chan_ctrl(u32 ch_no, enum aspeed_udma_ops op) -+{ -+ aspeed_udma_chan_ctrl(ch_no, op, false); ++ return 0; +} -+EXPORT_SYMBOL(aspeed_udma_rx_chan_ctrl); + -+static irqreturn_t aspeed_udma_isr(int irq, void *arg) ++static void update_host_ros(struct aspeed_mmbi_channel *chan, unsigned int w_len, ++ unsigned int r_len) +{ -+ 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); ++ struct device *dev = chan->dev; ++ struct host_ros hros; ++ u32 h2b_rp, b2h_wp; + -+ if (udma != (struct aspeed_udma *)arg) -+ return IRQ_NONE; ++ b2h_wp = GET_B2H_WRITE_POINTER(chan); ++ h2b_rp = GET_H2B_READ_POINTER(chan); + -+ if (tx_sts == 0 && rx_sts == 0) -+ return IRQ_NONE; ++ /* 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; + -+ 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); -+ } ++ /* 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; + -+ 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); -+ } ++ 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); + -+ return IRQ_HANDLED; ++ if (w_len != 0) ++ raise_b2h_interrupt(chan); +} + -+static int aspeed_udma_probe(struct platform_device *pdev) ++static int aspeed_mmbi_write(struct aspeed_mmbi_channel *chan, char *buffer, size_t len, ++ protocol_type type) +{ -+ int i, rc; -+ uint32_t reg; -+ struct resource *res; -+ struct device *dev = &pdev->dev; -+ -+ 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; -+ } ++ 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; + -+ 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); ++ /* 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; + } + -+ /* disable for safety */ -+ writel(0x0, udma->regs + UDMA_TX_DMA_EN); -+ writel(0x0, udma->regs + UDMA_RX_DMA_EN); ++ get_b2h_avail_buf_len(chan, &avail_buf_len); + -+ udma->irq = platform_get_irq(pdev, 0); -+ if (udma->irq < 0) { -+ dev_err(dev, "failed to get IRQ number\n"); -+ return -ENODEV; -+ } ++ dev_dbg(dev, "B2H buffer empty space: %ld\n", avail_buf_len); + -+ 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; -+ } ++ /* Header size */ ++ total_len = len + 4; + -+ /* -+ * 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); ++ padding = total_len & 0x3; ++ if (padding) ++ padding = 4 - padding; ++ total_len += padding; + -+ 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)); -+ } ++ /* 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; + -+ writel(0xffffffff, udma->regs + UDMA_TX_DMA_RST); -+ writel(0x0, udma->regs + UDMA_TX_DMA_RST); ++ /* Fill multi-protocol header */ ++ header.pkt_type = type; ++ header.pkt_len = total_len >> 2; ++ header.pkt_pad = padding; + -+ writel(0xffffffff, udma->regs + UDMA_RX_DMA_RST); -+ writel(0x0, udma->regs + UDMA_RX_DMA_RST); ++ wt_offset = GET_B2H_WRITE_POINTER(chan); ++ end_offset = chan->b2h_cb_size; + -+ 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); ++ /* 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); ++ } + -+ writel(UDMA_TMOUT, udma->regs + UDMA_TMOUT_TIMER); ++ /* 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); + -+ spin_lock_init(&udma->lock); ++ wt_offset = 0; ++ memcpy_toio(&chan->b2h_cb_vmem[wt_offset], buffer + chunk_len, len - chunk_len); ++ wt_offset += len - chunk_len; ++ } + -+ dev_set_drvdata(dev, udma); ++ update_host_ros(chan, total_len, 0); + + return 0; +} + -+static const struct of_device_id aspeed_udma_match[] = { -+ { .compatible = "aspeed,ast2500-udma" }, -+ { .compatible = "aspeed,ast2600-udma" }, -+ { .compatible = "aspeed,ast2700-udma" }, -+ { }, -+}; -+ -+static struct platform_driver aspeed_udma_driver = { -+ .driver = { -+ .name = DEVICE_NAME, -+ .of_match_table = aspeed_udma_match, ++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 h2b_rp; + -+ }, -+ .probe = aspeed_udma_probe, -+}; ++ 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; + -+module_platform_driver(aspeed_udma_driver); ++ /* 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); + -+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-04-08 18:03:48.311705302 +0000 -@@ -0,0 +1,152 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright 2021 Aspeed Technology Inc. -+ */ ++ 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; + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++ 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); + -+#define USB_HP_BEHCI84 0x84 /* Controller Fine-tune Register */ ++ rd_offset = 0; ++ memcpy_fromio(buffer + chunk_len, chan->h2b_cb_vmem + rd_offset, len - chunk_len); ++ } + -+static const struct of_device_id aspeed_usb_hp_dt_ids[] = { -+ { -+ .compatible = "aspeed,ast2600-usb2ahp", -+ }, -+ { -+ .compatible = "aspeed,ast2700-usb3ahp", -+ }, -+ { -+ .compatible = "aspeed,ast2700-usb3bhp", -+ }, -+ { -+ .compatible = "aspeed,ast2700-usb2ahp", -+ }, -+ { -+ .compatible = "aspeed,ast2700-usb2bhp", -+ }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, aspeed_usb_hp_dt_ids); ++ update_host_ros(chan, 0, len + sizeof(struct mmbi_header) + padding); ++} + -+static int aspeed_usb_hp_probe(struct platform_device *pdev) ++static void mctp_mmbi_rx(struct aspeed_mmbi_channel *chan) +{ -+ 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; ++ 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; + -+ if (of_device_is_compatible(pdev->dev.of_node, -+ "aspeed,ast2600-usb2ahp")) { -+ dev_info(&pdev->dev, "Initialized AST2600 USB2AHP\n"); -+ return 0; -+ } ++ if (get_mmbi_header(chan, &req_data_len, &type, &unread_data_len, &padding) != 0) ++ return; + -+ 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); ++ dev_dbg(chan->dev, "%s: Length: 0x%0x, Protocol Type: %d, Unread data: %d\n", __func__, ++ req_data_len, type, unread_data_len); + -+ rc = clk_prepare_enable(clk); -+ if (rc) { -+ dev_err(&pdev->dev, "Unable to enable clock (%d)\n", rc); -+ return rc; ++ 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; + } + -+ 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; ++ 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); + -+ 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; -+ } ++ cb = __mctp_cb(skb); ++ cb->halen = 0; + -+ 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)); ++ status = netif_rx(skb); ++ if (status == NET_RX_SUCCESS) { ++ ndev->stats.rx_packets++; ++ ndev->stats.rx_bytes += req_data_len; + } else { -+ ehci_32bits_quirk = -+ device_property_read_bool(&pdev->dev, "aspeed,ehci_32bits_quirk"); ++ ndev->stats.rx_dropped++; ++ } ++} + -+ if (ehci_32bits_quirk) { -+ regs = of_iomap(node, 0); -+ val = readl(regs + USB_HP_BEHCI84) & ~BIT(11); -+ writel(val, regs + USB_HP_BEHCI84); -+ } ++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; + -+ //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)); ++ if (!mmbi_get_host_rdy(&mctp->mmbi->chan) || skb->len > MCTP_MMBI_MTU_MAX) { ++ ndev->stats.tx_dropped++; ++ goto out; + } -+ dev_info(&pdev->dev, "Initialized AST2700 USB Host PCIe\n"); -+ return 0; -+err: -+ if (clk) -+ clk_disable_unprepare(clk); -+ return rc; ++ ++ 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 void aspeed_usb_hp_remove(struct platform_device *pdev) ++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) +{ -+ dev_info(&pdev->dev, "Remove USB Host PCIe\n"); ++ 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 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); ++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; + -+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-04-08 18:03:48.311705302 +0000 -@@ -0,0 +1,112 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright 2021 Aspeed Technology Inc. -+ */ ++ 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; + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++ mctp = netdev_priv(ndev); ++ mctp->ndev = ndev; ++ mctp->mmbi = chan->mmbi; + -+struct usb_phy_ctrl { -+ u32 offset; -+ u32 value; -+}; ++ chan->ndev = ndev; + -+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); ++ ret = register_netdev(ndev); ++ if (ret) ++ goto free_netdev; + -+static int aspeed_usb_phy_probe(struct platform_device *pdev) ++ return 0; ++ ++free_netdev: ++ free_netdev(ndev); ++ ++ return ret; ++} ++ ++static void aspeed_mmbi_work_func(struct work_struct *workq) +{ -+ 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; ++ 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; + -+ 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; -+ } ++ for (i = 0; i < weight; i++) { ++ if (get_mmbi_header(chan, &req_data_len, &type, &unread_data_len, &padding) != 0) ++ return; + -+ 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; -+ } ++ dev_dbg(chan->dev, "%s: Length: 0x%0x, Protocol Type: %d\n", ++ __func__, req_data_len, type); + -+ 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; -+ } ++ 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); + -+ 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; ++ raise_b2h_interrupt(chan); + } + -+ ctrl_data = devm_kzalloc(&pdev->dev, -+ sizeof(struct usb_phy_ctrl) * ctrl_num, -+ GFP_KERNEL); -+ if (!ctrl_data) -+ return -ENOMEM; ++ if (get_mmbi_header(chan, &req_data_len, &type, &unread_data_len, &padding) != 0) ++ queue_work(system_unbound_wq, &chan->work); ++} + -+ base = of_iomap(node, 0); ++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; + -+ 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; ++ 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); ++ } + } + -+ for (i = 0; i < ctrl_num; i++) -+ writel(ctrl_data[i].value, base + ctrl_data[i].offset); ++ if (mmbi_state_check(chan)) ++ return IRQ_HANDLED; + -+ dev_info(&pdev->dev, "Initialized USB PHY\n"); ++ queue_work(system_unbound_wq, &chan->work); + -+ return 0; ++ return IRQ_HANDLED; +} + -+static void aspeed_usb_phy_remove(struct platform_device *pdev) ++static void mmbi_desc_init(struct aspeed_mmbi_channel *chan) +{ -+} ++ struct mmbi_cap_desc desc; + -+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); ++ memset(&desc, 0, sizeof(struct mmbi_cap_desc)); + -+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 2026-04-08 18:03:48.311705302 +0000 -@@ -0,0 +1,1438 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+// Copyright IBM Corp 2019 ++ 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; + -+#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 ++ /* Per MMBI protoco spec, Set it to "#MMBI$" */ ++ memcpy(desc.signature, MMBI_SIGNATURE, sizeof(desc.signature)); + -+#define DEVICE_NAME "aspeed-xdma" ++ memcpy_toio(chan->desc_vmem, &desc, sizeof(desc)); ++} + -+#define SCU_AST2600_MISC_CTRL 0x0c0 -+#define SCU_AST2600_MISC_CTRL_XDMA_BMC BIT(8) -+#define SCU_AST2700_MISC_CTRL_XDMA_CLIENT BIT(4) ++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; + -+#define SCU_AST2600_DEBUG_CTRL 0x0c8 -+#define DEBUG_CTRL_AST2600_XDMA_DISABLE BIT(2) -+#define DEBUG_CTRL_AST2700_XDMA_DISABLE BIT(8) ++ b2h_vaddr = mmbi->mem_virt; ++ h2b_vaddr = b2h_vaddr + b2h_size; + -+#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) ++ 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); + -+#define SCU_AST2700_PCIE0_CTRL 0xa60 -+#define SCU_AST2700_PCIE1_CTRL 0xae0 -+#define SCU_AST2700_PCIE_CTRL_DMA_EN BIT(2) ++ 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); + -+#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 ++ 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); + -+#define XDMA_CMDQ_SIZE PAGE_SIZE -+#define XDMA_NUM_CMDS \ -+ (XDMA_CMDQ_SIZE / sizeof(struct aspeed_xdma_cmd)) ++ 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); + -+/* Aspeed specification requires 100us after disabling the reset */ -+#define XDMA_ENGINE_SETUP_TIME_MAX_US 1000 -+#define XDMA_ENGINE_SETUP_TIME_MIN_US 100 ++ /* Initialize the MMBI channel descriptor */ ++ mmbi_desc_init(chan); + -+#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) ++ /* Clear HRWS & HROS */ ++ mmbi_clear_hros(chan); ++ mmbi_clear_hrws(chan); + -+#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) ++ /* Initialize MTCP function */ ++ ret = aspeed_mmbi_mctp_init(chan); ++ if (ret) { ++ dev_err(dev, "Unable to init mctp\n"); ++ return ret; ++ } + -+#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) ++ /* Set BMC UP bit */ ++ mmbi_set_bmc_up(chan, 1); + -+#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 ++ return 0; ++} + -+#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 ++/* ++ * 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) ++ */ ++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 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 ++ /* 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 */ + -+struct aspeed_xdma_cmd { -+ u64 host_addr; -+ u64 pitch; -+ u64 cmd; -+ u64 reserved; -+}; ++ 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); ++ } + -+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; -+}; ++ 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; ++ } + -+struct aspeed_xdma_status_bits { -+ u32 us_comp; -+ u32 ds_comp; -+ u32 ds_dirty; -+}; ++ 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; ++ } + -+struct aspeed_xdma; ++ 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; ++ } + -+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); -+}; ++ 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); ++ } else { ++ regmap_write(mmbi->device, 0x18, 0x0C0C0027); ++ regmap_write(mmbi->device, 0x78, ASPEED_SCU_INT_EN | ASPEED_SCU_DECODE_DEV); ++ } + -+struct aspeed_xdma_client; ++ /* MSI */ ++ regmap_update_bits(mmbi->device, 0x74, GENMASK(7, 4), BIT(7) | (5 << 4)); + -+struct aspeed_xdma { -+ struct kobject kobj; -+ const struct aspeed_xdma_chip *chip; ++ regmap_update_bits(mmbi->device, 0x70, BIT(25) | BIT(17) | BIT(9) | BIT(1), ++ BIT(25) | BIT(17) | BIT(9) | BIT(1)); + -+ 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; ++ /* 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); + -+ /* Protects current_client */ -+ spinlock_t client_lock; -+ struct aspeed_xdma_client *current_client; ++ /* 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); + -+ /* Protects engine configuration */ -+ spinlock_t engine_lock; -+ struct aspeed_xdma_cmd *cmdq; -+ unsigned int cmd_idx; -+ bool in_reset; -+ bool upstream; ++ 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; ++ } + -+ /* Queue waiters for idle engine */ -+ wait_queue_head_t wait; ++ INIT_WORK(&chan->work, aspeed_mmbi_work_func); + -+ struct work_struct reset_work; ++ return 0; ++} + -+ 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 aspeed_platform ast2700_platform = { ++ .mmbi_init = aspeed_ast2700_pcie_mmbi_init, ++}; + -+ struct miscdevice misc; ++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); + -+struct aspeed_xdma_client { -+ struct aspeed_xdma *ctx; ++static int aspeed_pcie_mmbi_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; + -+ bool error; -+ bool in_progress; -+ void *virt; -+ dma_addr_t phys; -+ u32 size; -+}; ++ md = of_device_get_match_data(dev); ++ if (!md) ++ return -ENODEV; + -+#define CREATE_TRACE_POINTS -+#include ++ mmbi = devm_kzalloc(&pdev->dev, sizeof(struct aspeed_pcie_mmbi), GFP_KERNEL); ++ if (!mmbi) ++ return -ENOMEM; ++ dev_set_drvdata(dev, mmbi); + -+static u32 aspeed_xdma_readl(struct aspeed_xdma *ctx, u8 reg) -+{ -+ u32 v = readl(ctx->base + reg); ++ mmbi->dev = dev; ++ mmbi->platform = md; + -+ dev_dbg(ctx->dev, "read %02x[%08x]\n", reg, v); -+ return v; -+} ++ /* 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; ++ } + -+static void aspeed_xdma_writel(struct aspeed_xdma *ctx, u8 reg, u32 val) -+{ -+ writel(val, ctx->base + reg); -+ dev_dbg(ctx->dev, "write %02x[%08x]\n", reg, val); -+} ++ of_node_put(np); + -+static void aspeed_xdma_init_eng(struct aspeed_xdma *ctx) -+{ -+ unsigned long flags; ++ 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; ++ } + -+ 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 ++ /* 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; ++ } ++ 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; ++ } + -+ ctx->cmd_idx = 0; -+ spin_unlock_irqrestore(&ctx->engine_lock, flags); -+} ++ chan = &mmbi->chan; ++ memset(chan, 0, sizeof(struct aspeed_mmbi_channel)); + -+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) -+{ -+ 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; ++ 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; ++ } + -+ 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); ++ ret = mmbi->platform->mmbi_init(pdev); ++ if (ret) { ++ dev_err(dev, "Initialize pcie mmbi failed\n"); ++ goto out_irq; ++ } + -+ if (op->len > XDMA_CMD_AST2500_CMD_LINE_SIZE) { -+ unsigned int rem; -+ unsigned int total; ++ dev_info(dev, "ASPEED PCIe MMBI Dev %d: driver successfully loaded.\n", mmbi->id); + -+ 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; ++ 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; ++} + -+ if (rem) { -+ u32 rbmc = bmc_addr + total; ++static void aspeed_pcie_mmbi_remove(struct platform_device *pdev) ++{ ++ struct aspeed_pcie_mmbi *mmbi = platform_get_drvdata(pdev); + -+ 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; ++ 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); ++} + -+ print_hex_dump_debug("xdma rem ", DUMP_PREFIX_OFFSET, -+ 16, 1, &cmds[1], sizeof(*cmds), -+ true); ++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, ++ }, ++}; + -+ cmd &= ~(XDMA_CMD_AST2500_CMD_IRQ_EN | -+ XDMA_CMD_AST2500_CMD_IRQ_BMC); ++module_platform_driver(aspeed_pcie_mmbi_driver); + -+ rc++; -+ } -+ } ++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__ + -+ 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; ++#define MMBI_SIGNATURE "#MMBI$" + -+ print_hex_dump_debug("xdma cmd ", DUMP_PREFIX_OFFSET, 16, 1, cmds, -+ sizeof(*cmds), true); ++//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 + -+ return rc; -+} ++#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) + -+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) -+{ -+ 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); ++#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) + -+ if (op->host_addr & 0xffffffff00000000ULL || -+ (op->host_addr + (u64)op->len) & 0xffffffff00000000ULL) -+ cmd |= XDMA_CMD_AST2600_CMD_64_EN; ++#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) + -+ 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); ++#define GET_HOST_READY_BIT(x) (MMBI_HRWS1(x) & 0x01) ++#define GET_BMC_READY_BIT(x) (MMBI_HROS1(x) & 0x01) + -+ if ((op->host_addr & 0xff) + op->len > XDMA_CMD_AST2600_CMD_LINE_SIZE) { -+ unsigned int rem; -+ unsigned int total; ++typedef u8 protocol_type; + -+ 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; ++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, ++}; + -+ if (rem) { -+ u32 rbmc = bmc_addr + total; ++struct mmbi_header { ++ u32 pkt_pad : 2; ++ u32 pkt_len : 22; ++ u32 pkt_type : 4; ++ u32 reserved : 4; ++}; + -+ 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; ++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 */ ++}; + -+ print_hex_dump_debug("xdma rem ", DUMP_PREFIX_OFFSET, -+ 16, 1, &cmds[1], sizeof(*cmds), -+ true); ++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 */ ++}; + -+ cmd &= ~XDMA_CMD_AST2600_CMD_IRQ_BMC; ++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; + -+ rc++; -+ } -+ } ++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; + -+ 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; ++struct aspeed_pcie_mmbi; + -+ print_hex_dump_debug("xdma cmd ", DUMP_PREFIX_OFFSET, 16, 1, cmds, -+ sizeof(*cmds), true); ++#define MCTP_MMBI_MTU 65536 ++#define MCTP_MMBI_MTU_MIN 68 /* base mtu (64) + mctp header */ ++#define MCTP_MMBI_MTU_MAX 65536 + -+ return rc; -+} ++struct aspeed_mmbi_mctp { ++ struct aspeed_pcie_mmbi *mmbi; ++ struct net_device *ndev; ++}; + -+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); ++struct aspeed_mmbi_channel { ++ struct aspeed_pcie_mmbi *mmbi; ++ struct device *dev; + -+ if (op->host_addr & 0xffffffff00000000ULL || -+ (op->host_addr + (u64)op->len) & 0xffffffff00000000ULL) -+ cmd |= XDMA_CMD_AST2700_CMD_64_EN; ++ 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; + -+ 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); ++ bool bmc_int_en; ++ u8 bmc_int_value; ++ u32 bmc_int_location; ++ u8 __iomem *bmc_int_vmem; + -+ if (op->len > XDMA_CMD_AST2700_CMD_LINE_SIZE) { -+ unsigned int rem; -+ unsigned int total; ++ bool host_int_en; ++ u8 host_int_location; ++ u8 host_int_value; + -+ 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; ++ enum mmbi_state state; + -+ if (rem) { -+ u64 rbmc = bmc_addr + total; ++ /* MCTP */ ++ struct net_device *ndev; + -+ 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; ++ struct work_struct work; ++}; + -+ print_hex_dump_debug("xdma rem ", DUMP_PREFIX_OFFSET, -+ 16, 1, &cmds[1], sizeof(*cmds), -+ true); ++#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. + -+ cmd &= ~XDMA_CMD_AST2700_CMD_IRQ_BMC; ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ 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 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) + -+ print_hex_dump_debug("xdma cmd ", DUMP_PREFIX_OFFSET, 16, 1, cmds, -+ sizeof(*cmds), true); ++#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) + -+ return rc; ++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 aspeed_xdma_start(struct aspeed_xdma *ctx, unsigned int num_cmds, -+ struct aspeed_xdma_cmd cmds[2], bool upstream, -+ struct aspeed_xdma_client *client) ++static int ast_ssp_release(struct inode *inode, struct file *file) +{ -+ unsigned int i; -+ int rc = -EBUSY; -+ unsigned long flags; ++ return 0; ++} + -+ spin_lock_irqsave(&ctx->engine_lock, flags); -+ if (ctx->in_reset) -+ goto unlock; ++static const struct file_operations ast_ssp_fops = { ++ .owner = THIS_MODULE, ++ .open = ast_ssp_open, ++ .release = ast_ssp_release, ++ .llseek = noop_llseek, ++}; + -+ spin_lock(&ctx->client_lock); -+ if (ctx->current_client) { -+ spin_unlock(&ctx->client_lock); -+ goto unlock; -+ } ++struct miscdevice ast_ssp_misc = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "ast-ssp", ++ .fops = &ast_ssp_fops, ++}; + -+ client->error = false; -+ client->in_progress = true; -+ ctx->current_client = client; -+ spin_unlock(&ctx->client_lock); ++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; + -+ 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; -+ } ++ dev_info(priv->dev, "isr %x\n", isr); ++ writel(isr, priv->cvic + AST2600_CVIC_PENDING_CLEAR); + -+ aspeed_xdma_writel(ctx, ctx->chip->regs.bmc_cmdq_writep, -+ ctx->cmd_idx * ctx->chip->queue_entry_size); -+ rc = 0; ++ dev_info(priv->dev, "[CA7] rx addr:%08x, tx addr:%08x\n", ++ (u32)ssp_shared_mem_rx, (u32)ssp_shared_mem_tx); + -+unlock: -+ spin_unlock_irqrestore(&ctx->engine_lock, flags); -+ return rc; ++ /* 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 void aspeed_xdma_done(struct aspeed_xdma *ctx, bool error) ++static int ast_ssp_probe(struct platform_device *pdev) +{ -+ unsigned long flags; ++ 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; + -+ 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; ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) { ++ ret = -ENOMEM; ++ goto finish; + } -+ spin_unlock_irqrestore(&ctx->client_lock, flags); + -+ wake_up_interruptible_all(&ctx->wait); -+} ++ 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); + -+static irqreturn_t aspeed_xdma_irq(int irq, void *arg) -+{ -+ struct aspeed_xdma *ctx = arg; -+ u32 status; ++ 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); + -+ spin_lock(&ctx->engine_lock); -+ status = aspeed_xdma_readl(ctx, ctx->chip->regs.status); ++ 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; ++ } + -+ trace_xdma_irq(status); ++ 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; ++ } + -+ if (status & ctx->chip->status_bits.ds_dirty) { -+ aspeed_xdma_done(ctx, true); ++ 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 { -+ if (status & ctx->chip->status_bits.us_comp) { -+ if (ctx->upstream) -+ aspeed_xdma_done(ctx, false); ++ 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 (status & ctx->chip->status_bits.ds_comp) { -+ if (!ctx->upstream) -+ aspeed_xdma_done(ctx, false); -+ } ++ 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; + } + -+ aspeed_xdma_writel(ctx, ctx->chip->regs.status, status); -+ spin_unlock(&ctx->engine_lock); ++ 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); + -+ return IRQ_HANDLED; -+} ++ 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; ++ } + -+static void aspeed_xdma_reset(struct aspeed_xdma *ctx) -+{ -+ unsigned long flags; ++ memcpy(priv->ssp_mem_vir_addr, (void *)firmware->data, firmware->size); ++ release_firmware(firmware); + -+ trace_xdma_reset(ctx); ++ np = of_parse_phandle(mnode, "aspeed,cvic", 0); ++ if (!np) { ++ dev_err(priv->dev, "can't find CVIC\n"); ++ ret = -EINVAL; ++ goto finish; ++ } + -+ 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); ++ 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; ++ } + -+ aspeed_xdma_init_eng(ctx); ++ 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); + -+ aspeed_xdma_done(ctx, true); ++ 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); + -+ spin_lock_irqsave(&ctx->engine_lock, flags); -+ ctx->in_reset = false; -+ spin_unlock_irqrestore(&ctx->engine_lock, flags); ++ regmap_write(priv->scu, SSP_CACHE_RANGE_REG, SSP_CACHE_1ST_16MB_ENABLE); + -+ wake_up_interruptible(&ctx->wait); ++ 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 void aspeed_xdma_reset_work(struct work_struct *work) ++static void ast_ssp_remove(struct platform_device *pdev) +{ -+ struct aspeed_xdma *ctx = container_of(work, struct aspeed_xdma, -+ reset_work); ++ struct ast2600_ssp *priv = platform_get_drvdata(pdev); ++ int i; + -+ aspeed_xdma_reset(ctx); -+} ++ 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); + -+static irqreturn_t aspeed_xdma_pcie_irq(int irq, void *arg) -+{ -+ struct aspeed_xdma *ctx = arg; ++ kfree(priv); + -+ trace_xdma_perst(ctx); ++ misc_deregister((struct miscdevice *)&ast_ssp_misc); ++} + -+ spin_lock(&ctx->engine_lock); -+ if (ctx->in_reset) { -+ spin_unlock(&ctx->engine_lock); -+ return IRQ_HANDLED; -+ } ++static const struct of_device_id of_ast_ssp_match_table[] = { ++ { .compatible = "aspeed,ast2600-ssp", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, of_ast_ssp_match_table); + -+ ctx->in_reset = true; -+ spin_unlock(&ctx->engine_lock); ++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, ++ }, ++}; + -+ schedule_work(&ctx->reset_work); -+ return IRQ_HANDLED; -+} ++module_platform_driver(ast_ssp_driver); + -+static ssize_t aspeed_xdma_write(struct file *file, const char __user *buf, -+ size_t len, loff_t *offset) -+{ -+ 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; ++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, ++ }, ++}; + -+ if (len != sizeof(op)) -+ return -EINVAL; ++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 (READ_ONCE(client->in_progress)) -+ return -EBUSY; ++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, ++ }, ++}; + -+ if (copy_from_user(&op, buf, len)) -+ return -EFAULT; ++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 (!op.len || op.len > client->size || -+ op.direction > ASPEED_XDMA_DIRECTION_UPSTREAM) -+ return -EINVAL; ++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, ++ }, ++}; + -+ 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; ++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, ++ }, ++}; + -+ if ((file->f_flags & O_NONBLOCK) || rc != -EBUSY) -+ return rc; ++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, ++ }, ++}; + -+ rc = wait_event_interruptible(ctx->wait, -+ !(ctx->current_client || -+ ctx->in_reset)); -+ } while (!rc); ++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, ++ }, ++}; + -+ if (rc) -+ return -EINTR; ++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, ++ }, ++}; + -+ if (!(file->f_flags & O_NONBLOCK)) { -+ rc = wait_event_interruptible(ctx->wait, !client->in_progress); -+ if (rc) -+ return -EINTR; ++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, ++ }, ++}; + -+ if (client->error) -+ return -EIO; -+ } ++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 len; -+} ++static const struct attribute_group ast2700n0_uart_routing_attr_group = { ++ .attrs = ast2700n0_uart_routing_attrs, ++}; + -+static __poll_t aspeed_xdma_poll(struct file *file, -+ struct poll_table_struct *wait) -+{ -+ __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; ++/* 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 (req & (EPOLLIN | EPOLLRDNORM)) { -+ if (READ_ONCE(client->in_progress)) -+ poll_wait(file, &ctx->wait, wait); ++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, ++ }, ++}; + -+ if (!READ_ONCE(client->in_progress)) { -+ if (READ_ONCE(client->error)) -+ mask |= EPOLLERR; -+ else -+ mask |= EPOLLIN | EPOLLRDNORM; -+ } -+ } ++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 (req & (EPOLLOUT | EPOLLWRNORM)) { -+ if (READ_ONCE(ctx->current_client)) -+ poll_wait(file, &ctx->wait, wait); ++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, ++ }, ++}; + -+ if (!READ_ONCE(ctx->current_client)) -+ mask |= EPOLLOUT | EPOLLWRNORM; -+ } ++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 (mask) -+ aspeed_xdma_reset(ctx); ++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, ++ }, ++}; + -+ return mask; -+} ++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 long aspeed_xdma_ioctl(struct file *file, unsigned int cmd, -+ unsigned long param) -+{ -+ unsigned long flags; -+ struct aspeed_xdma_client *client = file->private_data; -+ struct aspeed_xdma *ctx = client->ctx; ++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, ++ }, ++}; + -+ 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; -+ } ++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, ++ }, ++}; + -+ ctx->in_reset = true; -+ spin_unlock_irqrestore(&ctx->engine_lock, flags); ++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, ++ }, ++}; + -+ if (READ_ONCE(ctx->current_client)) -+ dev_warn(ctx->dev, -+ "User reset with transfer in progress.\n"); ++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, ++}; + -+ aspeed_xdma_reset(ctx); -+ break; -+ default: -+ return -EINVAL; -+ } ++static const struct attribute_group ast2700n1_uart_routing_attr_group = { ++ .attrs = ast2700n1_uart_routing_attrs, ++}; + -+ return 0; -+} + 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 + -+static void aspeed_xdma_vma_close(struct vm_area_struct *vma) -+{ -+ int rc; -+ struct aspeed_xdma_client *client = vma->vm_private_data; ++#define DEVICE_NAME "aspeed-udma" + -+ rc = wait_event_interruptible(client->ctx->wait, !client->in_progress); -+ if (rc) -+ return; ++/* 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 + -+ gen_pool_free(client->ctx->pool, (unsigned long)client->virt, -+ client->size); -+ trace_xdma_unmap(client); ++#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) + -+ client->virt = NULL; -+ client->phys = 0; -+ client->size = 0; -+} ++#define UDMA_MAX_CHANNEL 16 ++#define UDMA_TMOUT 0x200 + -+static const struct vm_operations_struct aspeed_xdma_vm_ops = { -+ .close = aspeed_xdma_vma_close, ++enum aspeed_udma_bufsz_code { ++ UDMA_BUFSZ_CODE_1KB, ++ UDMA_BUFSZ_CODE_4KB, ++ UDMA_BUFSZ_CODE_16KB, ++ UDMA_BUFSZ_CODE_64KB, +}; + -+static int aspeed_xdma_mmap(struct file *file, struct vm_area_struct *vma) -+{ -+ int rc; -+ struct aspeed_xdma_client *client = file->private_data; -+ struct aspeed_xdma *ctx = client->ctx; ++struct aspeed_udma_chan { ++ dma_addr_t dma_addr; + -+ /* restrict file to one mapping */ -+ if (client->size) -+ return -EBUSY; ++ struct kfifo *fifo; ++ u32 fifo_sz; + -+ 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; -+ } ++ aspeed_udma_cb_t cb; ++ void *cb_arg; + -+ 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); ++ bool dis_tmout; ++}; + -+ 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); ++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; ++}; + -+ gen_pool_free(ctx->pool, (unsigned long)client->virt, -+ client->size); ++struct aspeed_udma udma[1]; + -+ trace_xdma_mmap_error(client, vma->vm_start); -+ client->virt = NULL; -+ client->phys = 0; -+ client->size = 0; -+ return rc; ++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; + } + -+ trace_xdma_mmap(client); -+ dev_dbg(ctx->dev, "mmap: v[%08lx] to p[%pa], s[%08x]\n", -+ vma->vm_start, &client->phys, client->size); -+ -+ return 0; ++ return -1; +} + -+static int aspeed_xdma_open(struct inode *inode, struct file *file) ++static u32 aspeed_udma_get_tx_rptr(u32 ch_no) +{ -+ 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; -+ -+ kobject_get(&ctx->kobj); -+ client->ctx = ctx; -+ file->private_data = client; -+ return 0; ++ return readl(udma->regs + UDMA_CHX_TX_RD_PTR(ch_no)); +} + -+static int aspeed_xdma_release(struct inode *inode, struct file *file) ++static u32 aspeed_udma_get_rx_wptr(u32 ch_no) +{ -+ 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); -+ -+ if (reset) -+ aspeed_xdma_reset(ctx); -+ -+ if (client->virt) { -+ gen_pool_free(ctx->pool, (unsigned long)client->virt, -+ client->size); -+ trace_xdma_unmap(client); -+ } ++ return readl(udma->regs + UDMA_CHX_RX_WR_PTR(ch_no)); ++} + -+ kfree(client); -+ kobject_put(&ctx->kobj); -+ return 0; ++static void aspeed_udma_set_ptr(u32 ch_no, u32 ptr, bool is_tx) ++{ ++ writel(ptr, udma->regs + ++ ((is_tx) ? UDMA_CHX_TX_WR_PTR(ch_no) : UDMA_CHX_RX_RD_PTR(ch_no))); +} + -+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) ++void aspeed_udma_set_tx_wptr(u32 ch_no, u32 wptr) +{ -+ struct regmap *scu = syscon_regmap_lookup_by_phandle(dev->of_node, -+ "aspeed,scu"); ++ aspeed_udma_set_ptr(ch_no, wptr, true); ++} ++EXPORT_SYMBOL(aspeed_udma_set_tx_wptr); + -+ 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; ++void aspeed_udma_set_rx_rptr(u32 ch_no, u32 rptr) ++{ ++ aspeed_udma_set_ptr(ch_no, rptr, false); ++} ++EXPORT_SYMBOL(aspeed_udma_set_rx_rptr); + -+ 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; -+ } -+ } ++static int aspeed_udma_free_chan(u32 ch_no, bool is_tx) ++{ ++ u32 reg; ++ unsigned long flags; + -+ 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; -+ } ++ if (ch_no > UDMA_MAX_CHANNEL) ++ return -EINVAL; + -+ regmap_update_bits(scu, ctx->chip->scu_pcie_conf, bmc | vga, -+ selection); ++ spin_lock_irqsave(&udma->lock, flags); + -+ 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); ++ reg = readl(udma->regs + ++ ((is_tx) ? UDMA_TX_DMA_INT_EN : UDMA_RX_DMA_INT_EN)); ++ reg &= ~(0x1 << ch_no); + -+ regmap_update_bits(scu, SCU_AST2600_DEBUG_CTRL, -+ ctx->chip->scu_disable_mask, 0); -+ } ++ writel(reg, udma->regs + ++ ((is_tx) ? UDMA_TX_DMA_INT_EN : UDMA_RX_DMA_INT_EN)); + -+ 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)); -+ } ++ spin_unlock_irqrestore(&udma->lock, flags); + + return 0; +} + -+static void aspeed_xdma_kobject_release(struct kobject *kobj) ++int aspeed_udma_free_tx_chan(u32 ch_no) +{ -+ struct aspeed_xdma *ctx = container_of(kobj, struct aspeed_xdma, kobj); ++ return aspeed_udma_free_chan(ch_no, true); ++} ++EXPORT_SYMBOL(aspeed_udma_free_tx_chan); + -+ if (ctx->pcie_irq >= 0) -+ free_irq(ctx->pcie_irq, ctx); ++int aspeed_udma_free_rx_chan(u32 ch_no) ++{ ++ return aspeed_udma_free_chan(ch_no, false); ++} ++EXPORT_SYMBOL(aspeed_udma_free_rx_chan); + -+ gen_pool_free(ctx->pool, (unsigned long)ctx->cmdq, XDMA_CMDQ_SIZE); ++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) ++{ ++ int retval = 0; ++ int fifosz_code; + -+ gen_pool_destroy(ctx->pool); ++ u32 reg; ++ unsigned long flags; ++ struct aspeed_udma_chan *ch; + -+ dma_free_coherent(ctx->dev, ctx->mem_size, ctx->mem_virt, -+ ctx->mem_coherent); ++ if (ch_no > UDMA_MAX_CHANNEL) { ++ retval = -EINVAL; ++ goto out; ++ } + -+ if (ctx->reset_rc) -+ reset_control_put(ctx->reset_rc); -+ reset_control_put(ctx->reset); ++ if (IS_ERR_OR_NULL(fifo) || IS_ERR_OR_NULL(fifo->kfifo.data)) { ++ retval = -EINVAL; ++ goto out; ++ } + -+ clk_put(ctx->clock); ++ fifosz_code = aspeed_udma_get_bufsz_code(fifo_sz); ++ if (fifosz_code < 0) { ++ retval = -EINVAL; ++ goto out; ++ } + -+ free_irq(ctx->irq, ctx); ++ spin_lock_irqsave(&udma->lock, flags); + -+ iounmap(ctx->base); -+ release_mem_region(ctx->res_start, ctx->res_size); ++ if (is_tx) { ++ reg = readl(udma->regs + UDMA_TX_DMA_INT_EN); ++ if (reg & (0x1 << ch_no)) { ++ retval = -EBUSY; ++ goto unlock_n_out; ++ } + -+ kfree(ctx); -+} ++ reg |= (0x1 << ch_no); ++ writel(reg, udma->regs + UDMA_TX_DMA_INT_EN); + -+static const struct kobj_type aspeed_xdma_kobject_type = { -+ .release = aspeed_xdma_kobject_release, -+}; ++ 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)); + -+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); ++ 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; ++ } + -+ if (!res) -+ return -ENOMEM; ++ reg |= (0x1 << ch_no); ++ writel(reg, udma->regs + UDMA_RX_DMA_INT_EN); + -+ size = resource_size(res); -+ if (!request_mem_region(res->start, size, dev_name(ctx->dev))) -+ 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)); + -+ ctx->base = ioremap(res->start, size); -+ if (!ctx->base) { -+ release_mem_region(res->start, size); -+ return -ENOMEM; ++ writel(addr, udma->regs + UDMA_CHX_RX_BUF_ADDR(ch_no)); + } + -+ ctx->res_start = res->start; -+ ctx->res_size = size; ++ 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; + ++unlock_n_out: ++ spin_unlock_irqrestore(&udma->lock, flags); ++out: + return 0; +} + -+static int aspeed_xdma_probe(struct platform_device *pdev) ++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) +{ -+ 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; ++ return aspeed_udma_request_chan(ch_no, addr, fifo, fifo_sz, cb, id, ++ dis_tmout, true); ++} ++EXPORT_SYMBOL(aspeed_udma_request_tx_chan); + -+ if (!md) -+ return -ENODEV; ++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); ++} ++EXPORT_SYMBOL(aspeed_udma_request_rx_chan); + -+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); -+ if (!ctx) -+ return -ENOMEM; ++static void aspeed_udma_chan_ctrl(u32 ch_no, u32 op, bool is_tx) ++{ ++ 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; + -+ 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); ++ if (ch_no > UDMA_MAX_CHANNEL) ++ return; + -+ rc_f = of_find_property(dev->of_node, "pcie_rc", NULL) ? 1 : 0; ++ spin_lock_irqsave(&udma->lock, flags); + -+ rc = aspeed_xdma_iomap(ctx, pdev); -+ if (rc) { -+ dev_err(dev, "Failed to map registers.\n"); -+ goto err_nomap; -+ } ++ reg_en = readl(udma->regs + reg_en_off); ++ reg_rst = readl(udma->regs + reg_rst_off); + -+ 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; -+ } ++ 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); + -+ 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; -+ } ++ reg_rst |= (0x1 << ch_no); ++ writel(reg_rst, udma->regs + reg_rst_off); + -+ 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; -+ } ++ udelay(100); + -+ 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; ++ reg_rst &= ~(0x1 << ch_no); ++ writel(reg_rst, udma->regs + reg_rst_off); ++ break; ++ default: ++ break; + } + -+ 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; -+ } -+ } ++ spin_unlock_irqrestore(&udma->lock, flags); ++} + -+ 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; -+ } ++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); + -+ 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; -+ } ++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); + -+ ctx->mem_phys = mem->base; -+ ctx->mem_size = mem->size; ++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); + -+ rc = of_reserved_mem_device_init(dev); -+ if (rc) { -+ dev_err(dev, "Failed to init reserved memory.\n"); -+ goto err_nomem; -+ } ++ if (udma != (struct aspeed_udma *)arg) ++ return IRQ_NONE; + -+ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); -+ if (rc) { -+ dev_err(dev, "Failed to mask DMA.\n"); -+ goto err_nomem; -+ } ++ if (tx_sts == 0 && rx_sts == 0) ++ return IRQ_NONE; + -+ 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; ++ 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); + } + -+ 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; ++ 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); + } + -+ 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; -+ } ++ return IRQ_HANDLED; ++} + -+ rc = aspeed_xdma_init_scu(ctx, dev); -+ if (rc) -+ goto err_pool_scu_clk; ++static int aspeed_udma_probe(struct platform_device *pdev) ++{ ++ int i, rc; ++ uint32_t reg; ++ struct resource *res; ++ struct device *dev = &pdev->dev; + -+ rc = clk_prepare_enable(ctx->clock); -+ if (rc) { -+ dev_err(dev, "Failed to enable the clock.\n"); -+ goto err_pool_scu_clk; ++ 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; + } + -+ 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); ++ 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); + } + -+ 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); ++ /* disable for safety */ ++ writel(0x0, udma->regs + UDMA_TX_DMA_EN); ++ writel(0x0, udma->regs + UDMA_RX_DMA_EN); + -+ 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; ++ udma->irq = platform_get_irq(pdev, 0); ++ if (udma->irq < 0) { ++ dev_err(dev, "failed to get IRQ number\n"); ++ return -ENODEV; + } + -+ aspeed_xdma_init_eng(ctx); -+ -+ id = of_alias_get_id(dev->of_node, "xdma"); -+ if (id < 0) -+ id = 0; -+ -+ 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); ++ rc = devm_request_irq(dev, udma->irq, aspeed_udma_isr, ++ IRQF_SHARED, DEVICE_NAME, udma); + if (rc) { -+ dev_err(dev, "Failed to register xdma miscdevice.\n"); -+ goto err_misc; ++ dev_err(dev, "failed to request IRQ handler\n"); ++ return rc; + } + + /* -+ * This interrupt could fire immediately so only request it once the -+ * engine and driver are initialized. ++ * For legacy design. ++ * - TX ringbuffer size: 4KB ++ * - RX ringbuffer size: 64KB ++ * - Timeout timer disabled + */ -+ 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; -+ } -+ } -+ -+ 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); -+ return rc; -+} -+ -+static void aspeed_xdma_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); ++ 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); + -+ aspeed_xdma_done(ctx, true); ++ 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)); ++ } + -+ misc_deregister(&ctx->misc); -+ kobject_put(&ctx->kobj); -+} ++ writel(0xffffffff, udma->regs + UDMA_TX_DMA_RST); ++ writel(0x0, udma->regs + UDMA_TX_DMA_RST); + -+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, -+}; ++ writel(0xffffffff, udma->regs + UDMA_RX_DMA_RST); ++ writel(0x0, udma->regs + UDMA_RX_DMA_RST); + -+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, -+}; ++ 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); + -+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, -+}; ++ writel(UDMA_TMOUT, udma->regs + UDMA_TMOUT_TIMER); + -+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, -+}; ++ spin_lock_init(&udma->lock); + -+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, -+ }, ++ dev_set_drvdata(dev, udma); ++ ++ return 0; ++} ++ ++static const struct of_device_id aspeed_udma_match[] = { ++ { .compatible = "aspeed,ast2500-udma" }, ++ { .compatible = "aspeed,ast2600-udma" }, ++ { .compatible = "aspeed,ast2700-udma" }, + { }, +}; + -+static struct platform_driver aspeed_xdma_driver = { -+ .probe = aspeed_xdma_probe, -+ .remove = aspeed_xdma_remove, ++static struct platform_driver aspeed_udma_driver = { + .driver = { + .name = DEVICE_NAME, -+ .of_match_table = aspeed_xdma_match, ++ .of_match_table = aspeed_udma_match, ++ + }, ++ .probe = aspeed_udma_probe, +}; + -+module_platform_driver(aspeed_xdma_driver); ++module_platform_driver(aspeed_udma_driver); + -+MODULE_AUTHOR("Eddie James"); -+MODULE_DESCRIPTION("ASPEED XDMA Engine Driver"); ++MODULE_AUTHOR("Chia-Wei Wang "); +MODULE_LICENSE("GPL"); -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-04-08 18:03:48.312705284 +0000 -@@ -0,0 +1,638 @@ -+// SPDX-License-Identifier: GPL-2.0 ++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 (C) ASPEED Technology Inc. ++ * Copyright 2021 Aspeed Technology Inc. + */ + -+#include -+#include -+#include -+#include ++#include ++#include +#include -+#include -+#include -+#include -+#include +#include -+#include ++#include ++#include +#include -+#include -+#include -+ -+#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 ++#include ++#include ++#include ++#include + -+#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 ++#define USB_HP_BEHCI84 0x84 /* Controller Fine-tune Register */ + -+struct aspeed_otp { -+ struct miscdevice miscdev; -+ void __iomem *reg_base; -+ bool is_open; -+ u32 otp_ver; -+ u32 *data; ++static const struct of_device_id aspeed_usb_hp_dt_ids[] = { ++ { ++ .compatible = "aspeed,ast2600-usb2ahp", ++ }, ++ { ++ .compatible = "aspeed,ast2700-usb3ahp", ++ }, ++ { ++ .compatible = "aspeed,ast2700-usb3bhp", ++ }, ++ { ++ .compatible = "aspeed,ast2700-usb2ahp", ++ }, ++ { ++ .compatible = "aspeed,ast2700-usb2bhp", ++ }, ++ {} +}; ++MODULE_DEVICE_TABLE(of, aspeed_usb_hp_dt_ids); + -+static DEFINE_SPINLOCK(otp_state_lock); -+ -+static inline u32 aspeed_otp_read(struct aspeed_otp *ctx, u32 reg) ++static int aspeed_usb_hp_probe(struct platform_device *pdev) +{ -+ int val; -+ -+ val = readl(ctx->reg_base + reg); -+ // printk("read:reg = 0x%08x, val = 0x%08x\n", reg, val); -+ return val; -+} ++ 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; + -+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); -+} ++ if (of_device_is_compatible(pdev->dev.of_node, ++ "aspeed,ast2600-usb2ahp")) { ++ dev_info(&pdev->dev, "Initialized AST2600 USB2AHP\n"); ++ return 0; ++ } + -+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; ++ 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; + } -+ return -1; -+} ++ clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(clk)) ++ return PTR_ERR(clk); + -+static void wait_complete(struct aspeed_otp *ctx) -+{ -+ int reg; -+ int i = 0; ++ rc = clk_prepare_enable(clk); ++ if (rc) { ++ dev_err(&pdev->dev, "Unable to enable clock (%d)\n", rc); ++ return rc; ++ } + -+ do { -+ reg = aspeed_otp_read(ctx, OTP_STATUS); -+ if ((reg & 0x6) == 0x6) -+ i++; -+ } while (i != 2); -+} ++ 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; + -+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); -+} ++ 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; ++ } + -+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; ++ 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 { -+ 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; ++ 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); + } -+ } + -+ wait_complete(ctx); ++ //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 int verify_bit(struct aspeed_otp *ctx, u32 otp_addr, int bit_offset, int value) ++static void aspeed_usb_hp_remove(struct platform_device *pdev) +{ -+ u32 ret[2]; -+ -+ 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 ++ dev_info(&pdev->dev, "Remove USB Host PCIe\n"); ++} + -+ 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); ++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); + -+ 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; -+ } -+} ++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+ ++/* ++ * Copyright 2021 Aspeed Technology Inc. ++ */ + -+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); -+} ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+static void _otp_prog_bit(struct aspeed_otp *ctx, u32 value, u32 prog_address, u32 bit_offset) -+{ -+ int prog_bit; ++struct usb_phy_ctrl { ++ u32 offset; ++ u32 value; ++}; + -+ 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); -+} ++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 otp_prog_bit(struct aspeed_otp *ctx, u32 value, u32 prog_address, u32 bit_offset) ++static int aspeed_usb_phy_probe(struct platform_device *pdev) +{ -+ int pass; -+ int i; -+ -+ otp_soak(ctx, 1); -+ _otp_prog_bit(ctx, value, prog_address, bit_offset); -+ pass = 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; + -+ 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; -+ } ++ 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; + } -+ otp_soak(ctx, 0); -+ return pass; -+} + -+static void otp_read_conf_dw(struct aspeed_otp *ctx, u32 offset, u32 *buf) -+{ -+ u32 config_offset; ++ 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; ++ } + -+ config_offset = 0x800; -+ config_offset |= (offset / 8) * 0x200; -+ config_offset |= (offset % 8) * 0x2; ++ 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; ++ } + -+ 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); -+} ++ 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 void otp_read_conf(struct aspeed_otp *ctx, u32 offset, u32 len) -+{ -+ int i, j; ++ ctrl_data = devm_kzalloc(&pdev->dev, ++ sizeof(struct usb_phy_ctrl) * ctrl_num, ++ GFP_KERNEL); ++ if (!ctrl_data) ++ return -ENOMEM; + -+ otp_soak(ctx, 0); -+ for (i = offset, j = 0; j < len; i++, j++) -+ otp_read_conf_dw(ctx, i, &ctx->data[j]); -+} ++ base = of_iomap(node, 0); + -+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); -+} ++ 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 void otp_read_data(struct aspeed_otp *ctx, u32 offset, u32 len) -+{ -+ int i, j; -+ u32 ret[2]; ++ for (i = 0; i < ctrl_num; i++) ++ writel(ctrl_data[i].value, base + ctrl_data[i].offset); + -+ otp_soak(ctx, 0); ++ dev_info(&pdev->dev, "Initialized USB PHY\n"); + -+ 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]); ++ return 0; +} + -+static int otp_prog_data(struct aspeed_otp *ctx, u32 value, u32 dw_offset, u32 bit_offset) ++static void aspeed_usb_phy_remove(struct platform_device *pdev) +{ -+ u32 read[2]; -+ int otp_bit; ++} + -+ if (dw_offset % 2 == 0) { -+ otp_read_data_2dw(ctx, dw_offset, read); -+ otp_bit = (read[0] >> bit_offset) & 0x1; ++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); + -+ 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; ++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 + -+ 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; -+ } ++#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 + -+ return otp_prog_bit(ctx, value, dw_offset, bit_offset); -+} ++#define DEVICE_NAME "aspeed-xdma" + -+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; ++#define SCU_AST2600_MISC_CTRL 0x0c0 ++#define SCU_AST2600_MISC_CTRL_XDMA_BMC BIT(8) ++#define SCU_AST2700_MISC_CTRL_XDMA_CLIENT BIT(4) + -+ otp_read_conf_dw(ctx, dw_offset, &read); ++#define SCU_AST2600_DEBUG_CTRL 0x0c8 ++#define DEBUG_CTRL_AST2600_XDMA_DISABLE BIT(2) ++#define DEBUG_CTRL_AST2700_XDMA_DISABLE BIT(8) + -+ 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; -+ } ++#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) + -+ return otp_prog_bit(ctx, value, prog_address, bit_offset); -+} ++#define SCU_AST2700_PCIE0_CTRL 0xa60 ++#define SCU_AST2700_PCIE1_CTRL 0xae0 ++#define SCU_AST2700_PCIE_CTRL_DMA_EN BIT(2) + -+struct aspeed_otp *glob_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 + -+void otp_read_data_buf(u32 offset, u32 *buf, u32 len) -+{ -+ int i, j; -+ u32 ret[2]; ++#define XDMA_CMDQ_SIZE PAGE_SIZE ++#define XDMA_NUM_CMDS \ ++ (XDMA_CMDQ_SIZE / sizeof(struct aspeed_xdma_cmd)) + -+ aspeed_otp_write(glob_ctx, OTP_PASSWD, OTP_PROTECT_KEY); ++/* Aspeed specification requires 100us after disabling the reset */ ++#define XDMA_ENGINE_SETUP_TIME_MAX_US 1000 ++#define XDMA_ENGINE_SETUP_TIME_MIN_US 100 + -+ otp_soak(glob_ctx, 0); ++#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) + -+ 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); ++#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) + -+void otp_read_conf_buf(u32 offset, u32 *buf, u32 len) -+{ -+ int i, j; ++#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) + -+ 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); ++#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 + -+static long 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_read xfer; -+ struct otp_prog prog; -+ u32 reg_read[2]; -+ int ret = 0; ++#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 + -+ 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; -+ } ++#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 + -+ 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); ++struct aspeed_xdma_cmd { ++ u64 host_addr; ++ u64 pitch; ++ u64 cmd; ++ u64 reserved; ++}; + -+ 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; -+ } ++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; ++}; + -+ 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); ++struct aspeed_xdma_status_bits { ++ u32 us_comp; ++ u32 ds_comp; ++ u32 ds_dirty; ++}; + -+ 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; -+} ++struct aspeed_xdma; + -+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); ++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); ++}; + -+ spin_lock(&otp_state_lock); ++struct aspeed_xdma_client; + -+ if (ctx->is_open) { -+ spin_unlock(&otp_state_lock); -+ return -EBUSY; -+ } ++struct aspeed_xdma { ++ struct kobject kobj; ++ const struct aspeed_xdma_chip *chip; + -+ ctx->is_open = true; ++ 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; + -+ spin_unlock(&otp_state_lock); ++ /* Protects current_client */ ++ spinlock_t client_lock; ++ struct aspeed_xdma_client *current_client; + -+ return 0; -+} ++ /* Protects engine configuration */ ++ spinlock_t engine_lock; ++ struct aspeed_xdma_cmd *cmdq; ++ unsigned int cmd_idx; ++ bool in_reset; ++ bool upstream; + -+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); ++ /* Queue waiters for idle engine */ ++ wait_queue_head_t wait; + -+ spin_lock(&otp_state_lock); ++ struct work_struct reset_work; + -+ ctx->is_open = false; ++ 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; + -+ spin_unlock(&otp_state_lock); ++ struct miscdevice misc; ++}; + -+ return 0; -+} ++struct aspeed_xdma_client { ++ struct aspeed_xdma *ctx; + -+static const struct file_operations otp_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = otp_ioctl, -+ .open = otp_open, -+ .release = otp_release, ++ bool error; ++ bool in_progress; ++ void *virt; ++ dma_addr_t phys; ++ u32 size; +}; + -+static const struct of_device_id aspeed_otp_of_matches[] = { -+ { .compatible = "aspeed,ast2600-sbc" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, aspeed_otp_of_matches); ++#define CREATE_TRACE_POINTS ++#include + -+static int aspeed_otp_probe(struct platform_device *pdev) ++static u32 aspeed_xdma_readl(struct aspeed_xdma *ctx, u8 reg) +{ -+ struct device *dev = &pdev->dev; -+ struct regmap *scu; -+ struct aspeed_otp *priv; -+ struct resource *res; -+ u32 revid0, revid1; -+ int rc; -+ -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ glob_ctx = priv; -+ if (!priv) -+ return -ENOMEM; ++ u32 v = readl(ctx->base + reg); + -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) { -+ dev_err(&pdev->dev, "cannot get IORESOURCE_MEM\n"); -+ return -ENOENT; -+ } ++ dev_dbg(ctx->dev, "read %02x[%08x]\n", reg, v); ++ return v; ++} + -+ priv->reg_base = devm_ioremap_resource(&pdev->dev, res); -+ if (!priv->reg_base) -+ return -EIO; ++static void aspeed_xdma_writel(struct aspeed_xdma *ctx, u8 reg, u32 val) ++{ ++ writel(val, ctx->base + reg); ++ dev_dbg(ctx->dev, "write %02x[%08x]\n", reg, val); ++} + -+ 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); -+ } ++static void aspeed_xdma_init_eng(struct aspeed_xdma *ctx) ++{ ++ unsigned long flags; + -+ regmap_read(scu, ASPEED_REVISION_ID0, &revid0); -+ regmap_read(scu, ASPEED_REVISION_ID1, &revid1); ++ 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 + -+ priv->otp_ver = chip_version(revid0, revid1); ++ ctx->cmd_idx = 0; ++ spin_unlock_irqrestore(&ctx->engine_lock, flags); ++} + -+ if (priv->otp_ver == -1) { -+ dev_err(dev, "invalid SCU\n"); -+ return -EINVAL; -+ } ++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) ++{ ++ 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; + -+ priv->data = kmalloc(8192, GFP_KERNEL); -+ if (!priv->data) -+ return -ENOMEM; ++ 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); + -+ dev_set_drvdata(dev, priv); ++ if (op->len > XDMA_CMD_AST2500_CMD_LINE_SIZE) { ++ unsigned int rem; ++ unsigned int total; + -+ /* Set up the miscdevice */ -+ priv->miscdev.minor = MISC_DYNAMIC_MINOR; -+ priv->miscdev.name = "aspeed-otp"; -+ priv->miscdev.fops = &otp_fops; ++ 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; + -+ /* Register the device */ -+ rc = misc_register(&priv->miscdev); -+ if (rc) { -+ dev_err(dev, "Unable to register device\n"); -+ return rc; -+ } ++ 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 void aspeed_otp_remove(struct platform_device *pdev) -+{ -+ struct aspeed_otp *ctx = dev_get_drvdata(&pdev->dev); ++ print_hex_dump_debug("xdma rem ", DUMP_PREFIX_OFFSET, ++ 16, 1, &cmds[1], sizeof(*cmds), ++ true); + -+ kfree(ctx->data); -+ misc_deregister(&ctx->miscdev); -+} ++ cmd &= ~(XDMA_CMD_AST2500_CMD_IRQ_EN | ++ XDMA_CMD_AST2500_CMD_IRQ_BMC); + -+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, -+ }, -+}; ++ rc++; ++ } ++ } + -+module_platform_driver(aspeed_otp_driver); ++ 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; + -+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-04-08 18:03:48.312705284 +0000 -@@ -0,0 +1,565 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright 2024 Aspeed Technology Inc. -+ */ ++ print_hex_dump_debug("xdma cmd ", DUMP_PREFIX_OFFSET, 16, 1, cmds, ++ sizeof(*cmds), true); + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++ return rc; ++} + -+static DEFINE_SPINLOCK(otp_state_lock); ++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) ++{ ++ 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); + -+/*********************** -+ * * -+ * OTP regs definition * -+ * * -+ ***********************/ -+#define OTP_REG_SIZE 0x200 ++ if (op->host_addr & 0xffffffff00000000ULL || ++ (op->host_addr + (u64)op->len) & 0xffffffff00000000ULL) ++ cmd |= XDMA_CMD_AST2600_CMD_64_EN; + -+#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_dbg(ctx->dev, "xdma %s ast2600: bmc[%08llx] len[%08x] host[%016llx]\n", ++ op->direction ? "upstream" : "downstream", ++ bmc_addr, op->len, op->host_addr); + -+#define OTP_CMD_OFFSET 0x20 -+#define OTP_MASTER OTP_M0 ++ if ((op->host_addr & 0xff) + op->len > XDMA_CMD_AST2600_CMD_LINE_SIZE) { ++ unsigned int rem; ++ unsigned int total; + -+#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) ++ 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; + -+#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 (rem) { ++ u32 rbmc = bmc_addr + total; + -+#define OTP_PMC 0x400 -+#define OTP_DAP 0x500 ++ 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; + -+/* OTP status: [0] */ -+#define OTP_STS_IDLE 0x0 -+#define OTP_STS_BUSY 0x1 ++ print_hex_dump_debug("xdma rem ", DUMP_PREFIX_OFFSET, ++ 16, 1, &cmds[1], sizeof(*cmds), ++ true); + -+/* 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 ++ cmd &= ~XDMA_CMD_AST2600_CMD_IRQ_BMC; + -+/* OTP ECC EN */ -+#define ECC_ENABLE 0x1 -+#define ECC_DISABLE 0x0 -+#define ECCBRP_EN BIT(0) ++ rc++; ++ } ++ } + -+#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[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_MEMORY_SIZE (HW_PUF_REGION_END_ADDR * 2) ++ print_hex_dump_debug("xdma cmd ", DUMP_PREFIX_OFFSET, 16, 1, cmds, ++ sizeof(*cmds), true); + -+#define OTP_TIMEOUT_US 10000 ++ return rc; ++} + -+/* OTPSTRAP */ -+#define OTPSTRAP0_ADDR STRAP_REGION_START_ADDR -+#define OTPSTRAP14_ADDR (OTPSTRAP0_ADDR + 0xe) ++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 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 ++ if (op->host_addr & 0xffffffff00000000ULL || ++ (op->host_addr + (u64)op->len) & 0xffffffff00000000ULL) ++ cmd |= XDMA_CMD_AST2700_CMD_64_EN; + -+enum otp_error_code { -+ OTP_SUCCESS, -+ OTP_READ_FAIL, -+ OTP_PROG_FAIL, -+ OTP_CMP_FAIL, -+}; ++ 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); + -+enum aspeed_otp_master_id { -+ OTP_M0 = 0, -+ OTP_M1, -+ OTP_M2, -+ OTP_M3, -+ OTP_M4, -+ OTP_M5, -+ OTP_MID_MAX, -+}; ++ if (op->len > XDMA_CMD_AST2700_CMD_LINE_SIZE) { ++ unsigned int rem; ++ unsigned int total; + -+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; -+}; ++ 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; + -+enum otp_ioctl_cmds { -+ GET_ECC_STATUS = 1, -+ SET_ECC_ENABLE, -+}; ++ if (rem) { ++ u64 rbmc = bmc_addr + total; + -+enum otp_ecc_codes { -+ OTP_ECC_MISMATCH = -1, -+ OTP_ECC_DISABLE = 0, -+ OTP_ECC_ENABLE = 1, -+}; ++ 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 void otp_unlock(struct device *dev) -+{ -+ struct aspeed_otp *ctx = dev_get_drvdata(dev); ++ print_hex_dump_debug("xdma rem ", DUMP_PREFIX_OFFSET, ++ 16, 1, &cmds[1], sizeof(*cmds), ++ true); + -+ writel(OTP_PASSWD, ctx->base + OTP_KEY); -+} ++ cmd &= ~XDMA_CMD_AST2700_CMD_IRQ_BMC; + -+static void otp_lock(struct device *dev) -+{ -+ struct aspeed_otp *ctx = dev_get_drvdata(dev); ++ 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; + -+ writel(0x1, ctx->base + OTP_KEY); ++ print_hex_dump_debug("xdma cmd ", DUMP_PREFIX_OFFSET, 16, 1, cmds, ++ sizeof(*cmds), true); ++ ++ return rc; +} + -+static int wait_complete(struct device *dev) ++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) +{ -+ struct aspeed_otp *ctx = dev_get_drvdata(dev); -+ int ret; -+ u32 val; ++ unsigned int i; ++ int rc = -EBUSY; ++ unsigned long 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); ++ spin_lock_irqsave(&ctx->engine_lock, flags); ++ if (ctx->in_reset) ++ goto unlock; + -+ return ret; -+} ++ spin_lock(&ctx->client_lock); ++ if (ctx->current_client) { ++ spin_unlock(&ctx->client_lock); ++ goto unlock; ++ } + -+static int otp_read_data(struct aspeed_otp *ctx, u32 offset, u16 *data) -+{ -+ struct device *dev = ctx->dev; -+ int ret; ++ client->error = false; ++ client->in_progress = true; ++ ctx->current_client = client; ++ spin_unlock(&ctx->client_lock); + -+ 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; ++ 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; ++ } + -+ data[0] = readl(ctx->base + OTP_RDATA); ++ aspeed_xdma_writel(ctx, ctx->chip->regs.bmc_cmdq_writep, ++ ctx->cmd_idx * ctx->chip->queue_entry_size); ++ rc = 0; + -+ return 0; ++unlock: ++ spin_unlock_irqrestore(&ctx->engine_lock, flags); ++ return rc; +} + -+static int otp_prog_data(struct aspeed_otp *ctx, u32 offset, u16 data) ++static void aspeed_xdma_done(struct aspeed_xdma *ctx, bool error) +{ -+ struct device *dev = ctx->dev; -+ int ret; ++ unsigned long flags; + -+ 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; ++ 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); + -+ return 0; ++ wake_up_interruptible_all(&ctx->wait); +} + -+static int otp_prog_multi_data(struct aspeed_otp *ctx, u32 offset, u32 *data, int count) ++static irqreturn_t aspeed_xdma_irq(int irq, void *arg) +{ -+ struct device *dev = ctx->dev; -+ int ret; -+ -+ 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); ++ struct aspeed_xdma *ctx = arg; ++ u32 status; + -+ writel(OTP_CMD_PROG_MULTI, ctx->base + OTP_CMD); -+ ret = wait_complete(dev); -+ if (ret) -+ return OTP_PROG_FAIL; ++ spin_lock(&ctx->engine_lock); ++ status = aspeed_xdma_readl(ctx, ctx->chip->regs.status); + -+ return 0; -+} ++ trace_xdma_irq(status); + -+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; ++ 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); ++ } + -+ 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 (status & ctx->chip->status_bits.ds_comp) { ++ if (!ctx->upstream) ++ aspeed_xdma_done(ctx, false); + } + } + -+ otp_lock(dev); -+ return ret; ++ aspeed_xdma_writel(ctx, ctx->chip->regs.status, status); ++ spin_unlock(&ctx->engine_lock); ++ ++ return IRQ_HANDLED; +} + -+static int aspeed_otp_write(struct aspeed_otp *ctx, int offset, -+ const void *buf, int size) ++static void aspeed_xdma_reset(struct aspeed_xdma *ctx) +{ -+ struct device *dev = ctx->dev; -+ u32 *data32 = (u32 *)buf; -+ u16 *data = (u16 *)buf; -+ int ret; ++ unsigned long flags; + -+ otp_unlock(dev); ++ trace_xdma_reset(ctx); + -+ if (size == 1) -+ ret = otp_prog_data(ctx, offset, data[0]); -+ else -+ ret = otp_prog_multi_data(ctx, offset, data32, size / 2); ++ 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); + -+ if (ret) -+ dev_warn(ctx->dev, "prog failed\n"); ++ aspeed_xdma_init_eng(ctx); + -+ otp_lock(dev); -+ return ret; ++ 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 int aspeed_otp_ecc_en(struct aspeed_otp *ctx) ++static void aspeed_xdma_reset_work(struct work_struct *work) +{ -+ struct device *dev = ctx->dev; -+ int ret = 0; ++ struct aspeed_xdma *ctx = container_of(work, struct aspeed_xdma, ++ reset_work); + -+ /* Check ecc is already enabled */ -+ if (ctx->gbl_ecc_en == 1) -+ return 0; ++ aspeed_xdma_reset(ctx); ++} + -+ otp_unlock(dev); ++static irqreturn_t aspeed_xdma_pcie_irq(int irq, void *arg) ++{ ++ struct aspeed_xdma *ctx = arg; + -+ /* enable cfg ecc */ -+ ret = otp_prog_data(ctx, OTPSTRAP14_ADDR, 0x1); -+ if (ret) { -+ dev_warn(dev, "%s: prog failed\n", __func__); -+ goto end; ++ trace_xdma_perst(ctx); ++ ++ spin_lock(&ctx->engine_lock); ++ if (ctx->in_reset) { ++ spin_unlock(&ctx->engine_lock); ++ return IRQ_HANDLED; + } + -+ ctx->gbl_ecc_en = 1; -+end: -+ otp_lock(dev); ++ ctx->in_reset = true; ++ spin_unlock(&ctx->engine_lock); + -+ return ret; ++ schedule_work(&ctx->reset_work); ++ return IRQ_HANDLED; +} + -+static long aspeed_otp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++static ssize_t aspeed_xdma_write(struct file *file, const char __user *buf, ++ size_t len, loff_t *offset) +{ -+ 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; ++ 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; + -+ switch (cmd) { -+ case ASPEED_OTP_READ_DATA: -+ if (copy_from_user(&rdata, argp, sizeof(struct otp_read))) -+ return -EFAULT; ++ if (len != sizeof(op)) ++ return -EINVAL; + -+ ret = aspeed_otp_read(ctx, rdata.offset, ctx->data, rdata.len); -+ if (ret) -+ return -EFAULT; ++ if (READ_ONCE(client->in_progress)) ++ return -EBUSY; + -+ if (copy_to_user(rdata.data, ctx->data, rdata.len * 2)) -+ return -EFAULT; ++ if (copy_from_user(&op, buf, len)) ++ return -EFAULT; + -+ break; ++ if (!op.len || op.len > client->size || ++ op.direction > ASPEED_XDMA_DIRECTION_UPSTREAM) ++ return -EINVAL; + -+ case ASPEED_OTP_PROG_DATA: -+ if (copy_from_user(&pdata, argp, sizeof(struct otp_prog))) -+ 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; + -+ ret = aspeed_otp_write(ctx, pdata.w_offset, pdata.data, pdata.len); -+ break; ++ if ((file->f_flags & O_NONBLOCK) || rc != -EBUSY) ++ return rc; + -+ case ASPEED_OTP_GET_ECC: -+ if (copy_to_user(argp, &ctx->gbl_ecc_en, sizeof(ctx->gbl_ecc_en))) -+ return -EFAULT; -+ break; ++ rc = wait_event_interruptible(ctx->wait, ++ !(ctx->current_client || ++ ctx->in_reset)); ++ } while (!rc); + -+ case ASPEED_OTP_SET_ECC: -+ ret = aspeed_otp_ecc_en(ctx); -+ break; ++ if (rc) ++ return -EINTR; + -+ 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; ++ 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 ret; ++ return len; +} + -+static int aspeed_otp_ecc_init(struct device *dev) ++static __poll_t aspeed_xdma_poll(struct file *file, ++ struct poll_table_struct *wait) +{ -+ struct aspeed_otp *ctx = dev_get_drvdata(dev); -+ int ret; -+ u32 val; ++ __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; + -+ otp_unlock(dev); ++ if (req & (EPOLLIN | EPOLLRDNORM)) { ++ if (READ_ONCE(client->in_progress)) ++ 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(client->in_progress)) { ++ if (READ_ONCE(client->error)) ++ mask |= EPOLLERR; ++ else ++ mask |= EPOLLIN | EPOLLRDNORM; ++ } ++ } + -+ val = readl(ctx->base + OTP_RDATA); -+ if (val & 0x1) -+ ctx->gbl_ecc_en = 0x1; -+ else -+ ctx->gbl_ecc_en = 0x0; ++ if (req & (EPOLLOUT | EPOLLWRNORM)) { ++ if (READ_ONCE(ctx->current_client)) ++ poll_wait(file, &ctx->wait, wait); + -+ otp_lock(dev); ++ if (!READ_ONCE(ctx->current_client)) ++ mask |= EPOLLOUT | EPOLLWRNORM; ++ } + -+ return 0; ++ if (mask) ++ aspeed_xdma_reset(ctx); ++ ++ return mask; +} + -+static int aspeed_otp_open(struct inode *inode, struct file *file) ++static long aspeed_xdma_ioctl(struct file *file, unsigned int cmd, ++ unsigned long param) +{ -+ struct miscdevice *c = file->private_data; -+ struct aspeed_otp *ctx = container_of(c, struct aspeed_otp, miscdev); ++ unsigned long flags; ++ struct aspeed_xdma_client *client = file->private_data; ++ struct aspeed_xdma *ctx = client->ctx; + -+ spin_lock(&otp_state_lock); ++ 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; ++ } + -+ if (ctx->is_open) { -+ spin_unlock(&otp_state_lock); -+ return -EBUSY; -+ } ++ ctx->in_reset = true; ++ spin_unlock_irqrestore(&ctx->engine_lock, flags); + -+ ctx->is_open = true; ++ if (READ_ONCE(ctx->current_client)) ++ dev_warn(ctx->dev, ++ "User reset with transfer in progress.\n"); + -+ spin_unlock(&otp_state_lock); ++ aspeed_xdma_reset(ctx); ++ break; ++ default: ++ return -EINVAL; ++ } + + return 0; +} + -+static int aspeed_otp_release(struct inode *inode, struct file *file) ++static void aspeed_xdma_vma_close(struct vm_area_struct *vma) +{ -+ struct miscdevice *c = file->private_data; -+ struct aspeed_otp *ctx = container_of(c, struct aspeed_otp, miscdev); -+ -+ spin_lock(&otp_state_lock); ++ int rc; ++ struct aspeed_xdma_client *client = vma->vm_private_data; + -+ ctx->is_open = false; ++ rc = wait_event_interruptible(client->ctx->wait, !client->in_progress); ++ if (rc) ++ return; + -+ spin_unlock(&otp_state_lock); ++ gen_pool_free(client->ctx->pool, (unsigned long)client->virt, ++ client->size); ++ trace_xdma_unmap(client); + -+ return 0; ++ client->virt = NULL; ++ client->phys = 0; ++ client->size = 0; +} + -+static const struct file_operations otp_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = aspeed_otp_ioctl, -+ .open = aspeed_otp_open, -+ .release = aspeed_otp_release, -+}; -+ -+static const struct of_device_id aspeed_otp_of_matches[] = { -+ { .compatible = "aspeed,ast2700-otp" }, -+ { } ++static const struct vm_operations_struct aspeed_xdma_vm_ops = { ++ .close = aspeed_xdma_vma_close, +}; -+MODULE_DEVICE_TABLE(of, aspeed_otp_of_matches); + -+static int aspeed_otp_probe(struct platform_device *pdev) ++static int aspeed_xdma_mmap(struct file *file, struct vm_area_struct *vma) +{ -+ 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; + -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; ++ /* restrict file to one mapping */ ++ if (client->size) ++ return -EBUSY; + -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) { -+ dev_err(&pdev->dev, "cannot get IORESOURCE_MEM\n"); -+ return -ENOENT; ++ 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; + } + -+ priv->base = devm_ioremap_resource(&pdev->dev, res); -+ if (!priv->base) -+ return -EIO; ++ 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); + -+ 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); ++ 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); ++ ++ gen_pool_free(ctx->pool, (unsigned long)client->virt, ++ client->size); ++ ++ trace_xdma_mmap_error(client, vma->vm_start); ++ client->virt = NULL; ++ client->phys = 0; ++ client->size = 0; ++ return rc; + } + -+ regmap_read(scu0, 0x0, &priv->chip_revid0); -+ regmap_read(scu1, 0x0, &priv->chip_revid1); ++ trace_xdma_mmap(client); ++ dev_dbg(ctx->dev, "mmap: v[%08lx] to p[%pa], s[%08x]\n", ++ vma->vm_start, &client->phys, client->size); + -+ priv->dev = dev; -+ dev_set_drvdata(dev, priv); ++ return 0; ++} + -+ /* OTP ECC init */ -+ rc = aspeed_otp_ecc_init(dev); -+ if (rc) -+ return -EIO; ++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); + -+ priv->data = kmalloc(OTP_MEMORY_SIZE, GFP_KERNEL); -+ if (!priv->data) ++ if (!client) + return -ENOMEM; + -+ /* Set up the miscdevice */ -+ priv->miscdev.minor = MISC_DYNAMIC_MINOR; -+ priv->miscdev.name = "aspeed-otp"; -+ priv->miscdev.fops = &otp_fops; ++ kobject_get(&ctx->kobj); ++ client->ctx = ctx; ++ file->private_data = client; ++ return 0; ++} + -+ /* Register the device */ -+ rc = misc_register(&priv->miscdev); -+ if (rc) { -+ dev_err(dev, "Unable to register device\n"); -+ return rc; ++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); + -+ dev_info(dev, "Aspeed OTP driver successfully registered\n"); -+ -+ return 0; -+} ++ if (reset) ++ aspeed_xdma_reset(ctx); + -+static void aspeed_otp_remove(struct platform_device *pdev) -+{ -+ struct aspeed_otp *ctx = dev_get_drvdata(&pdev->dev); ++ if (client->virt) { ++ gen_pool_free(ctx->pool, (unsigned long)client->virt, ++ client->size); ++ trace_xdma_unmap(client); ++ } + -+ kfree(ctx->data); -+ misc_deregister(&ctx->miscdev); ++ kfree(client); ++ kobject_put(&ctx->kobj); ++ return 0; +} + -+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 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, +}; + -+module_platform_driver(aspeed_otp_driver); ++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"); + -+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-04-08 18:03:48.312705284 +0000 -@@ -0,0 +1,18 @@ -+menu "ASPEED eSPI drivers" ++ 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; + -+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. ++ 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; ++ } ++ } + -+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. ++ 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; ++ } + -+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-04-08 18:03:48.312705284 +0000 -@@ -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/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-04-08 18:03:48.312705284 +0000 -@@ -0,0 +1,207 @@ -+/* 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__ ++ regmap_update_bits(scu, ctx->chip->scu_pcie_conf, bmc | vga, ++ selection); + -+#include -+#include ++ 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); + -+/* -+ * 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 ++ regmap_update_bits(scu, SCU_AST2600_DEBUG_CTRL, ++ ctx->chip->scu_disable_mask, 0); ++ } + -+/* -+ * 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; -+}; ++ 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_mem32 { -+ u8 cyc; -+ u8 len_h : 4; -+ u8 tag : 4; -+ u8 len_l; -+ u32 addr_be; -+ u8 data[]; -+} __packed; ++ return 0; ++} + -+struct espi_perif_mem64 { -+ u8 cyc; -+ u8 len_h : 4; -+ u8 tag : 4; -+ u8 len_l; -+ u32 addr_be; -+ u8 data[]; -+} __packed; ++static void aspeed_xdma_kobject_release(struct kobject *kobj) ++{ ++ struct aspeed_xdma *ctx = container_of(kobj, struct aspeed_xdma, kobj); + -+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->pcie_irq >= 0) ++ free_irq(ctx->pcie_irq, ctx); + -+struct espi_perif_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); + -+struct espi_oob_msg { -+ u8 cyc; -+ u8 len_h : 4; -+ u8 tag : 4; -+ u8 len_l; -+ u8 data[]; -+}; ++ gen_pool_destroy(ctx->pool); + -+struct espi_flash_rwe { -+ u8 cyc; -+ u8 len_h : 4; -+ u8 tag : 4; -+ u8 len_l; -+ u32 addr_be; -+ u8 data[]; -+} __packed; ++ dma_free_coherent(ctx->dev, ctx->mem_size, ctx->mem_virt, ++ ctx->mem_coherent); + -+struct espi_flash_cmplt { -+ u8 cyc; -+ u8 len_h : 4; -+ u8 tag : 4; -+ u8 len_l; -+ u8 data[]; -+} __packed; ++ if (ctx->reset_rc) ++ reset_control_put(ctx->reset_rc); ++ reset_control_put(ctx->reset); + -+#define ESPI_MAX_PLD_LEN BIT(12) ++ clk_put(ctx->clock); + -+/* -+ * 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 ++ free_irq(ctx->irq, ctx); + -+/* -+ * 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) ++ iounmap(ctx->base); ++ release_mem_region(ctx->res_start, ctx->res_size); + -+struct aspeed_espi_ioc { -+ u32 pkt_len; -+ u8 *pkt; ++ kfree(ctx); ++} ++ ++static const struct kobj_type aspeed_xdma_kobject_type = { ++ .release = aspeed_xdma_kobject_release, +}; + -+/* -+ * 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, 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 -+/* -+ * 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) ++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); + -+#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-04-08 18:03:48.312705284 +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. -+ */ ++ if (!res) ++ return -ENOMEM; + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++ size = resource_size(res); ++ if (!request_mem_region(res->start, size, dev_name(ctx->dev))) ++ return -ENOMEM; + -+#include "aspeed-espi.h" -+#include "ast2500-espi.h" -+#include "ast2600-espi.h" -+#include "ast2700-espi.h" ++ ctx->base = ioremap(res->start, size); ++ if (!ctx->base) { ++ release_mem_region(res->start, size); ++ return -ENOMEM; ++ } + -+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); ++ ctx->res_start = res->start; ++ ctx->res_size = size; ++ ++ return 0; ++} + -+static int aspeed_espi_probe(struct platform_device *pdev) ++static int aspeed_xdma_probe(struct platform_device *pdev) +{ -+ const struct of_device_id *match; ++ int rc, id; ++ struct aspeed_xdma *ctx; ++ struct reserved_mem *mem; + struct device *dev = &pdev->dev; -+ struct aspeed_espi *espi; -+ struct resource *res; -+ int rc; ++ struct device_node *memory_region; ++ const void *md = of_device_get_match_data(dev); ++ bool rc_f; + -+ espi = devm_kzalloc(dev, sizeof(*espi), GFP_KERNEL); -+ if (!espi) ++ if (!md) ++ return -ENODEV; ++ ++ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) + return -ENOMEM; + -+ espi->dev = dev; -+ match = of_match_device(aspeed_espi_of_matches, dev); -+ if (!match) -+ return -ENODEV; -+ espi->ops = match->data; ++ 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->pdev = pdev; ++ rc_f = of_find_property(dev->of_node, "pcie_rc", NULL) ? 1 : 0; + -+ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); ++ rc = aspeed_xdma_iomap(ctx, pdev); + if (rc) { -+ dev_err(dev, "cannot set 64-bits DMA mask\n"); -+ return rc; ++ dev_err(dev, "Failed to map registers.\n"); ++ goto err_nomap; + } + -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) { -+ dev_err(dev, "cannot get resource\n"); -+ return -ENODEV; ++ 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; + } + -+ espi->regs = devm_ioremap_resource(dev, res); -+ if (IS_ERR(espi->regs)) { -+ dev_err(dev, "cannot map registers\n"); -+ return PTR_ERR(espi->regs); ++ 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; + } + -+ espi->irq = platform_get_irq(pdev, 0); -+ if (espi->irq < 0) { -+ dev_err(dev, "cannot get IRQ number\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->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); ++ 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->clk = devm_clk_get(dev, NULL); -+ if (IS_ERR(espi->clk)) { -+ dev_err(dev, "cannot get clock control\n"); -+ return PTR_ERR(espi->clk); ++ 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; ++ } + } + -+ rc = clk_prepare_enable(espi->clk); -+ if (rc) { -+ dev_err(dev, "cannot enable clocks\n"); -+ return rc; ++ 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; ++ } ++ ++ 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; + } + -+ espi->ops->espi_pre_init(espi); ++ ctx->mem_phys = mem->base; ++ ctx->mem_size = mem->size; + -+ rc = espi->ops->espi_perif_probe(espi); ++ rc = of_reserved_mem_device_init(dev); + if (rc) { -+ dev_err(dev, "cannot init peripheral channel, rc=%d\n", rc); -+ return rc; ++ dev_err(dev, "Failed to init reserved memory.\n"); ++ goto err_nomem; + } + -+ rc = espi->ops->espi_vw_probe(espi); ++ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (rc) { -+ dev_err(dev, "cannot init vw channel, rc=%d\n", rc); -+ goto err_remove_perif; ++ dev_err(dev, "Failed to mask DMA.\n"); ++ goto err_nomem; + } + -+ rc = espi->ops->espi_oob_probe(espi); -+ if (rc) { -+ dev_err(dev, "cannot init oob channel, rc=%d\n", rc); -+ goto err_remove_vw; ++ 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; ++ } ++ ++ 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_flash_probe(espi); ++ rc = gen_pool_add_virt(ctx->pool, (unsigned long)ctx->mem_virt, ++ ctx->mem_phys, ctx->mem_size, -1); + if (rc) { -+ dev_err(dev, "cannot init flash channel, rc=%d\n", rc); -+ goto err_remove_oob; ++ dev_err(ctx->dev, "Failed to add memory to genalloc pool.\n"); ++ goto err_pool_scu_clk; + } + -+ rc = devm_request_irq(dev, espi->irq, espi->ops->espi_isr, 0, -+ dev_name(dev), espi); ++ rc = aspeed_xdma_init_scu(ctx, dev); ++ if (rc) ++ goto err_pool_scu_clk; ++ ++ rc = clk_prepare_enable(ctx->clock); + if (rc) { -+ dev_err(dev, "cannot request IRQ\n"); -+ goto err_remove_flash; ++ dev_err(dev, "Failed to enable the clock.\n"); ++ goto err_pool_scu_clk; + } + -+ 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 (ctx->reset_rc) { ++ rc = reset_control_deassert(ctx->reset_rc); + if (rc) { -+ dev_err(dev, "cannot request MMBI IRQ\n"); -+ goto err_remove_flash; ++ 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); ++ } ++ ++ 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; ++ ++ 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; ++ } ++ ++ /* ++ * 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; + } + } + -+ espi->ops->espi_post_init(espi); ++ kobject_init(&ctx->kobj, &aspeed_xdma_kobject_type); ++ return 0; + -+ platform_set_drvdata(pdev, espi); ++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); ++ return rc; ++} + -+ dev_info(dev, "module loaded\n"); ++static void aspeed_xdma_remove(struct platform_device *pdev) ++{ ++ struct aspeed_xdma *ctx = platform_get_drvdata(pdev); + -+ return 0; ++ reset_control_assert(ctx->reset); ++ if (ctx->reset_rc) ++ reset_control_assert(ctx->reset_rc); ++ clk_disable_unprepare(ctx->clock); + -+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); ++ aspeed_xdma_done(ctx, true); + -+ return rc; ++ misc_deregister(&ctx->misc); ++ kobject_put(&ctx->kobj); +} + -+static void aspeed_espi_remove(struct platform_device *pdev) -+{ -+ struct aspeed_espi *espi; -+ struct device *dev; ++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, ++}; + -+ dev = &pdev->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, ++}; + -+ espi = dev_get_drvdata(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->ops->espi_deinit(espi); ++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, ++}; + -+ 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 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_espi_driver = { ++static struct platform_driver aspeed_xdma_driver = { ++ .probe = aspeed_xdma_probe, ++ .remove = aspeed_xdma_remove, + .driver = { -+ .name = "aspeed-espi", -+ .of_match_table = aspeed_espi_of_matches, ++ .name = DEVICE_NAME, ++ .of_match_table = aspeed_xdma_match, + }, -+ .probe = aspeed_espi_probe, -+ .remove = aspeed_espi_remove, +}; + -+module_platform_driver(aspeed_espi_driver); ++module_platform_driver(aspeed_xdma_driver); + -+MODULE_AUTHOR("Aspeed Technology Inc."); -+MODULE_DESCRIPTION("Aspeed eSPI controller (AST2500/2600/2700)"); ++MODULE_AUTHOR("Eddie James"); ++MODULE_DESCRIPTION("ASPEED XDMA Engine Driver"); +MODULE_LICENSE("GPL"); -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-04-08 18:03:48.312705284 +0000 -@@ -0,0 +1,227 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ +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+ +/* -+ * Unified eSPI driver header file and data structures -+ * Copyright 2026 Aspeed Technology Inc. ++ * Copyright 2023 Aspeed Technology Inc. + */ -+#ifndef __ASPEED_ESPI_H__ -+#define __ASPEED_ESPI_H__ -+ -+#include "linux/platform_device.h" -+#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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, -+}; ++#include ++#include ++#include ++#include ++#include + -+/* consistent with DTS property "flash-safs-mode" */ -+enum aspeed_edaf_mode { -+ EDAF_MODE_MIX = 0x0, -+ EDAF_MODE_SW, -+ EDAF_MODE_HW, -+ EDAF_MODES, -+}; ++#include "ast2500-espi.h" + -+struct aspeed_espi_perif; ++#define DEVICE_NAME "aspeed-espi" + -+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; -+}; ++#define PERIF_MCYC_UNLOCK 0xfedc756e ++#define PERIF_MCYC_ALIGN SZ_64K + -+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; ++#define FLASH_SAFS_ALIGN SZ_16M + ++struct ast2500_espi_perif { + struct { + bool enable; + void *virt; + dma_addr_t taddr; -+ dma_addr_t saddr; -+ resource_size_t size; ++ uint32_t saddr; ++ uint32_t size; + } mcyc; + + struct { @@ -75675,99 +66981,29 @@ diff --git a/drivers/soc/aspeed/espi/aspeed-espi.h b/drivers/soc/aspeed/espi/asp + 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 ++ spinlock_t lock; ++ struct mutex np_tx_mtx; ++ struct mutex pc_tx_mtx; ++ struct mutex pc_rx_mtx; + + struct miscdevice mdev; +}; + -+struct aspeed_espi_vw { ++struct ast2500_espi_vw { + struct { + bool hw_mode; -+ u32 grp; -+ u32 dir0; -+ u32 dir1; -+ u32 val0; -+ u32 val1; ++ uint32_t val; + } 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 ast2500_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; @@ -75777,19 +67013,19 @@ diff --git a/drivers/soc/aspeed/espi/aspeed-espi.h b/drivers/soc/aspeed/espi/asp + 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 ++ spinlock_t lock; ++ struct mutex tx_mtx; ++ struct mutex rx_mtx; + + struct miscdevice mdev; +}; + -+struct aspeed_espi_flash { ++struct ast2500_espi_flash { + struct { -+ u32 mode; ++ uint32_t mode; + phys_addr_t taddr; -+ resource_size_t size; -+ } edaf; ++ uint32_t size; ++ } safs; + + struct { + bool enable; @@ -75802,78 +67038,39 @@ diff --git a/drivers/soc/aspeed/espi/aspeed-espi.h b/drivers/soc/aspeed/espi/asp + 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 ++ spinlock_t lock; ++ struct mutex rx_mtx; ++ struct mutex tx_mtx; + + struct miscdevice mdev; +}; + -+struct aspeed_espi { -+ struct platform_device *pdev; ++struct ast2500_espi { + 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; ++ struct ast2500_espi_perif perif; ++ struct ast2500_espi_vw vw; ++ struct ast2500_espi_oob oob; ++ struct ast2500_espi_flash flash; +}; + -+#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-04-08 18:03:48.312705284 +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 aspeed_espi_perif *perif, ++ struct ast2500_espi_perif *perif, + struct aspeed_espi_ioc *ioc) +{ -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; ++ uint32_t reg, cyc, tag, len; ++ struct ast2500_espi *espi; + struct espi_comm_hdr *hdr; + unsigned long flags; -+ u32 pkt_len; -+ u8 *pkt; ++ uint32_t pkt_len; ++ uint8_t *pkt; + int i, rc; + -+ espi = container_of(perif, struct aspeed_espi, perif); ++ espi = container_of(perif, struct ast2500_espi, perif); + + if (fp->f_flags & O_NONBLOCK) { + if (!mutex_trylock(&perif->pc_rx_mtx)) @@ -75981,16 +67178,16 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as +} + +static long ast2500_espi_perif_pc_put_tx(struct file *fp, -+ struct aspeed_espi_perif *perif, ++ struct ast2500_espi_perif *perif, + struct aspeed_espi_ioc *ioc) +{ -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; ++ uint32_t reg, cyc, tag, len; ++ struct ast2500_espi *espi; + struct espi_comm_hdr *hdr; -+ u8 *pkt; ++ uint8_t *pkt; + int i, rc; + -+ espi = container_of(perif, struct aspeed_espi, perif); ++ espi = container_of(perif, struct ast2500_espi, perif); + + if (!mutex_trylock(&perif->pc_tx_mtx)) + return -EAGAIN; @@ -76048,16 +67245,16 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as +} + +static long ast2500_espi_perif_np_put_tx(struct file *fp, -+ struct aspeed_espi_perif *perif, ++ struct ast2500_espi_perif *perif, + struct aspeed_espi_ioc *ioc) +{ -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; ++ uint32_t reg, cyc, tag, len; ++ struct ast2500_espi *espi; + struct espi_comm_hdr *hdr; -+ u8 *pkt; ++ uint8_t *pkt; + int i, rc; + -+ espi = container_of(perif, struct aspeed_espi, perif); ++ espi = container_of(perif, struct ast2500_espi, perif); + + if (!mutex_trylock(&perif->np_tx_mtx)) + return -EAGAIN; @@ -76116,10 +67313,10 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + +static long ast2500_espi_perif_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ -+ struct aspeed_espi_perif *perif; ++ struct ast2500_espi_perif *perif; + struct aspeed_espi_ioc ioc; + -+ perif = container_of(fp->private_data, struct aspeed_espi_perif, mdev); ++ perif = container_of(fp->private_data, struct ast2500_espi_perif, mdev); + + if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) + return -EFAULT; @@ -76143,11 +67340,11 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + +static int ast2500_espi_perif_mmap(struct file *fp, struct vm_area_struct *vma) +{ -+ struct aspeed_espi_perif *perif; ++ struct ast2500_espi_perif *perif; + unsigned long vm_size; + pgprot_t vm_prot; + -+ perif = container_of(fp->private_data, struct aspeed_espi_perif, mdev); ++ perif = container_of(fp->private_data, struct ast2500_espi_perif, mdev); + if (!perif->mcyc.enable) + return -EPERM; + @@ -76173,11 +67370,11 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + .unlocked_ioctl = ast2500_espi_perif_ioctl, +}; + -+static void ast2500_espi_perif_isr(struct aspeed_espi *espi) ++static void ast2500_espi_perif_isr(struct ast2500_espi *espi) +{ -+ struct aspeed_espi_perif *perif; ++ struct ast2500_espi_perif *perif; + unsigned long flags; -+ u32 sts; ++ uint32_t sts; + + perif = &espi->perif; + @@ -76194,11 +67391,11 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + } +} + -+static void ast2500_espi_perif_reset(struct aspeed_espi *espi) ++static void ast2500_espi_perif_reset(struct ast2500_espi *espi) +{ -+ struct aspeed_espi_perif *perif; ++ struct ast2500_espi_perif *perif; + struct device *dev; -+ u32 reg, mask; ++ uint32_t reg, mask; + + dev = espi->dev; + @@ -76256,9 +67453,9 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + writel(reg, espi->regs + ESPI_CTRL); +} + -+int ast2500_espi_perif_probe(struct aspeed_espi *espi) ++static int ast2500_espi_perif_probe(struct ast2500_espi *espi) +{ -+ struct aspeed_espi_perif *perif; ++ struct ast2500_espi_perif *perif; + struct device *dev; + int rc; + @@ -76276,13 +67473,13 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + + 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", (u32 *)&perif->mcyc.saddr); ++ 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", (u32 *)&perif->mcyc.size); ++ 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; @@ -76335,11 +67532,11 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + return 0; +} + -+int ast2500_espi_perif_remove(struct aspeed_espi *espi) ++static int ast2500_espi_perif_remove(struct ast2500_espi *espi) +{ -+ struct aspeed_espi_perif *perif; ++ struct ast2500_espi_perif *perif; + struct device *dev; -+ u32 reg; ++ uint32_t reg; + + dev = espi->dev; + @@ -76381,21 +67578,21 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as +/* virtual wire channel (CH1) */ +static long ast2500_espi_vw_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ -+ struct aspeed_espi_vw *vw; -+ struct aspeed_espi *espi; -+ u32 gpio; ++ struct ast2500_espi_vw *vw; ++ struct ast2500_espi *espi; ++ uint32_t gpio; + -+ vw = container_of(fp->private_data, struct aspeed_espi_vw, mdev); -+ espi = container_of(vw, struct aspeed_espi, vw); -+ gpio = vw->gpio.val0; ++ vw = container_of(fp->private_data, struct ast2500_espi_vw, mdev); ++ espi = container_of(vw, struct ast2500_espi, vw); ++ gpio = vw->gpio.val; + + switch (cmd) { + case ASPEED_ESPI_VW_GET_GPIO_VAL: -+ if (put_user(gpio, (u32 __user *)arg)) ++ if (put_user(gpio, (uint32_t __user *)arg)) + return -EFAULT; + break; + case ASPEED_ESPI_VW_PUT_GPIO_VAL: -+ if (get_user(gpio, (u32 __user *)arg)) ++ if (get_user(gpio, (uint32_t __user *)arg)) + return -EFAULT; + + writel(gpio, espi->regs + ESPI_VW_GPIO_VAL); @@ -76412,10 +67609,10 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + .unlocked_ioctl = ast2500_espi_vw_ioctl, +}; + -+static void ast2500_espi_vw_isr(struct aspeed_espi *espi) ++static void ast2500_espi_vw_isr(struct ast2500_espi *espi) +{ -+ struct aspeed_espi_vw *vw; -+ u32 reg, sts, sts_sysevt; ++ struct ast2500_espi_vw *vw; ++ uint32_t reg, sts, sts_sysevt; + + vw = &espi->vw; + @@ -76452,22 +67649,22 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + } + + if (sts & ESPI_INT_STS_VW_GPIO) { -+ vw->gpio.val0 = readl(espi->regs + ESPI_VW_GPIO_VAL); ++ vw->gpio.val = 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 aspeed_espi *espi) ++static void ast2500_espi_vw_reset(struct ast2500_espi *espi) +{ -+ u32 reg; -+ struct aspeed_espi_vw *vw = &espi->vw; ++ uint32_t reg; ++ struct ast2500_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.val0 = readl(espi->regs + ESPI_VW_GPIO_VAL); ++ vw->gpio.val = 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) @@ -76504,11 +67701,11 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + writel(reg, espi->regs + ESPI_CTRL); +} + -+int ast2500_espi_vw_probe(struct aspeed_espi *espi) ++static int ast2500_espi_vw_probe(struct ast2500_espi *espi) +{ + int rc; + struct device *dev = espi->dev; -+ struct aspeed_espi_vw *vw = &espi->vw; ++ struct ast2500_espi_vw *vw = &espi->vw; + + writel(0x0, espi->regs + ESPI_VW_SYSEVT_INT_EN); + writel(0xffffffff, espi->regs + ESPI_VW_SYSEVT_INT_STS); @@ -76533,10 +67730,10 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + return 0; +} + -+int ast2500_espi_vw_remove(struct aspeed_espi *espi) ++static int ast2500_espi_vw_remove(struct ast2500_espi *espi) +{ -+ struct aspeed_espi_vw *vw; -+ u32 reg; ++ struct ast2500_espi_vw *vw; ++ uint32_t reg; + + vw = &espi->vw; + @@ -76551,18 +67748,18 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + +/* out-of-band channel (CH2) */ +static long ast2500_espi_oob_get_rx(struct file *fp, -+ struct aspeed_espi_oob *oob, ++ struct ast2500_espi_oob *oob, + struct aspeed_espi_ioc *ioc) +{ -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; ++ uint32_t reg, cyc, tag, len; ++ struct ast2500_espi *espi; + struct espi_comm_hdr *hdr; + unsigned long flags; -+ u32 pkt_len; -+ u8 *pkt; ++ uint32_t pkt_len; ++ uint8_t *pkt; + int i, rc; + -+ espi = container_of(oob, struct aspeed_espi, oob); ++ espi = container_of(oob, struct ast2500_espi, oob); + + if (fp->f_flags & O_NONBLOCK) { + if (!mutex_trylock(&oob->rx_mtx)) @@ -76648,16 +67845,16 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as +} + +static long ast2500_espi_oob_put_tx(struct file *fp, -+ struct aspeed_espi_oob *oob, ++ struct ast2500_espi_oob *oob, + struct aspeed_espi_ioc *ioc) +{ -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; ++ uint32_t reg, cyc, tag, len; ++ struct ast2500_espi *espi; + struct espi_comm_hdr *hdr; -+ u8 *pkt; ++ uint8_t *pkt; + int i, rc; + -+ espi = container_of(oob, struct aspeed_espi, oob); ++ espi = container_of(oob, struct ast2500_espi, oob); + + if (!mutex_trylock(&oob->tx_mtx)) + return -EAGAIN; @@ -76721,10 +67918,10 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + +static long ast2500_espi_oob_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ -+ struct aspeed_espi_oob *oob; ++ struct ast2500_espi_oob *oob; + struct aspeed_espi_ioc ioc; + -+ oob = container_of(fp->private_data, struct aspeed_espi_oob, mdev); ++ oob = container_of(fp->private_data, struct ast2500_espi_oob, mdev); + + if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) + return -EFAULT; @@ -76749,11 +67946,11 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + .unlocked_ioctl = ast2500_espi_oob_ioctl, +}; + -+static void ast2500_espi_oob_isr(struct aspeed_espi *espi) ++static void ast2500_espi_oob_isr(struct ast2500_espi *espi) +{ -+ struct aspeed_espi_oob *oob; ++ struct ast2500_espi_oob *oob; + unsigned long flags; -+ u32 sts; ++ uint32_t sts; + + oob = &espi->oob; + @@ -76770,10 +67967,10 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + } +} + -+static void ast2500_espi_oob_reset(struct aspeed_espi *espi) ++static void ast2500_espi_oob_reset(struct ast2500_espi *espi) +{ -+ struct aspeed_espi_oob *oob; -+ u32 reg; ++ struct ast2500_espi_oob *oob; ++ uint32_t reg; + + oob = &espi->oob; + @@ -76812,9 +68009,9 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + writel(reg, espi->regs + ESPI_CTRL); +} + -+int ast2500_espi_oob_probe(struct aspeed_espi *espi) ++static int ast2500_espi_oob_probe(struct ast2500_espi *espi) +{ -+ struct aspeed_espi_oob *oob; ++ struct ast2500_espi_oob *oob; + struct device *dev; + int rc; + @@ -76859,11 +68056,11 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + return 0; +} + -+int ast2500_espi_oob_remove(struct aspeed_espi *espi) ++static int ast2500_espi_oob_remove(struct ast2500_espi *espi) +{ -+ struct aspeed_espi_oob *oob; ++ struct ast2500_espi_oob *oob; + struct device *dev; -+ u32 reg; ++ uint32_t reg; + + dev = espi->dev; + @@ -76894,20 +68091,20 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + +/* flash channel (CH3) */ +static long ast2500_espi_flash_get_rx(struct file *fp, -+ struct aspeed_espi_flash *flash, ++ struct ast2500_espi_flash *flash, + struct aspeed_espi_ioc *ioc) +{ -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; ++ uint32_t reg, cyc, tag, len; ++ struct ast2500_espi *espi; + struct espi_comm_hdr *hdr; + unsigned long flags; -+ u32 pkt_len; -+ u8 *pkt; ++ uint32_t pkt_len; ++ uint8_t *pkt; + int i, rc; + + rc = 0; + -+ espi = container_of(flash, struct aspeed_espi, flash); ++ espi = container_of(flash, struct ast2500_espi, flash); + + if (fp->f_flags & O_NONBLOCK) { + if (!mutex_trylock(&flash->rx_mtx)) @@ -77016,16 +68213,16 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as +} + +static long ast2500_espi_flash_put_tx(struct file *fp, -+ struct aspeed_espi_flash *flash, ++ struct ast2500_espi_flash *flash, + struct aspeed_espi_ioc *ioc) +{ -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; ++ uint32_t reg, cyc, tag, len; ++ struct ast2500_espi *espi; + struct espi_comm_hdr *hdr; -+ u8 *pkt; ++ uint8_t *pkt; + int i, rc; + -+ espi = container_of(flash, struct aspeed_espi, flash); ++ espi = container_of(flash, struct ast2500_espi, flash); + + if (!mutex_trylock(&flash->tx_mtx)) + return -EAGAIN; @@ -77084,10 +68281,10 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + +static long ast2500_espi_flash_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ -+ struct aspeed_espi_flash *flash; ++ struct ast2500_espi_flash *flash; + struct aspeed_espi_ioc ioc; + -+ flash = container_of(fp->private_data, struct aspeed_espi_flash, mdev); ++ flash = container_of(fp->private_data, struct ast2500_espi_flash, mdev); + + if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) + return -EFAULT; @@ -77112,11 +68309,11 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + .unlocked_ioctl = ast2500_espi_flash_ioctl, +}; + -+static void ast2500_espi_flash_isr(struct aspeed_espi *espi) ++static void ast2500_espi_flash_isr(struct ast2500_espi *espi) +{ -+ struct aspeed_espi_flash *flash; ++ struct ast2500_espi_flash *flash; + unsigned long flags; -+ u32 sts; ++ uint32_t sts; + + flash = &espi->flash; + @@ -77133,10 +68330,10 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + } +} + -+static void ast2500_espi_flash_reset(struct aspeed_espi *espi) ++static void ast2500_espi_flash_reset(struct ast2500_espi *espi) +{ -+ struct aspeed_espi_flash *flash = &espi->flash; -+ u32 reg; ++ struct ast2500_espi_flash *flash = &espi->flash; ++ uint32_t reg; + + reg = readl(espi->regs + ESPI_INT_EN); + reg &= ~(ESPI_INT_EN_FLASH); @@ -77156,9 +68353,9 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + reg |= (ESPI_CTRL_FLASH_TX_SW_RST | ESPI_CTRL_FLASH_RX_SW_RST); + writel(reg, espi->regs + ESPI_CTRL); + -+ 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); ++ 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; @@ -77182,9 +68379,9 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + writel(reg, espi->regs + ESPI_CTRL); +} + -+int ast2500_espi_flash_probe(struct aspeed_espi *espi) ++static int ast2500_espi_flash_probe(struct ast2500_espi *espi) +{ -+ struct aspeed_espi_flash *flash; ++ struct ast2500_espi_flash *flash; + struct device *dev; + int rc; + @@ -77199,18 +68396,18 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + mutex_init(&flash->tx_mtx); + mutex_init(&flash->rx_mtx); + -+ flash->edaf.mode = EDAF_MODE_MIX; ++ flash->safs.mode = SAFS_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)) { ++ 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"); + 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)) { ++ 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; + } @@ -77246,11 +68443,11 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + return 0; +} + -+int ast2500_espi_flash_remove(struct aspeed_espi *espi) ++static int ast2500_espi_flash_remove(struct ast2500_espi *espi) +{ -+ struct aspeed_espi_flash *flash; ++ struct ast2500_espi_flash *flash; + struct device *dev; -+ u32 reg; ++ uint32_t reg; + + dev = espi->dev; + @@ -77280,12 +68477,12 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as +} + +/* global control */ -+irqreturn_t ast2500_espi_isr(int irq, void *arg) ++static irqreturn_t ast2500_espi_isr(int irq, void *arg) +{ -+ struct aspeed_espi *espi; -+ u32 sts; ++ struct ast2500_espi *espi; ++ uint32_t sts; + -+ espi = (struct aspeed_espi *)arg; ++ espi = (struct ast2500_espi *)arg; + + sts = readl(espi->regs + ESPI_INT_STS); + if (!sts) @@ -77314,47 +68511,180 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.c b/drivers/soc/aspeed/espi/as + return IRQ_HANDLED; +} + -+void ast2500_espi_pre_init(struct aspeed_espi *espi) ++static int ast2500_espi_probe(struct platform_device *pdev) +{ -+ u32 reg; ++ 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; ++ } + + 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; ++ 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; ++ } + + 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; +} + -+void ast2500_espi_deinit(struct aspeed_espi *espi) ++static int ast2500_espi_remove(struct platform_device *pdev) +{ -+ u32 reg; ++ struct ast2500_espi *espi; ++ struct device *dev; ++ uint32_t reg; ++ int rc; ++ ++ dev = &pdev->dev; ++ ++ espi = (struct ast2500_espi *)dev_get_drvdata(dev); + + 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; +} -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-04-08 18:03:48.312705284 +0000 -@@ -0,0 +1,258 @@ ++ ++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/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+ */ +/* -+ * 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" ++#include "aspeed-espi-comm.h" + +/* registers */ +#define ESPI_CTRL 0x000 @@ -77588,24 +68918,18 @@ diff --git a/drivers/soc/aspeed/espi/ast2500-espi.h b/drivers/soc/aspeed/espi/as + 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); ++/* consistent with DTS property "flash-safs-mode" */ ++enum ast2500_safs_mode { ++ SAFS_MODE_MIX = 0x0, ++ SAFS_MODE_SW, ++ SAFS_MODES, ++}; ++ +#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-04-08 18:03:48.313705265 +0000 -@@ -0,0 +1,1910 @@ +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. @@ -77629,8 +68953,8 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as +#include + +#include "ast2600-espi.h" -+#include "aspeed-espi-comm.h" -+#include "aspeed-espi.h" ++ ++#define DEVICE_NAME "aspeed-espi" + +#define PERIF_MCYC_ALIGN SZ_64K +#define PERIF_MMBI_ALIGN SZ_64K @@ -77640,22 +68964,170 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as +#define OOB_DMA_DESC_NUM 8 +#define OOB_DMA_DESC_CUSTOM 0x4 + -+#define FLASH_EDAF_ALIGN SZ_16M ++#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; ++}; + +/* 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; ++ struct ast2600_espi_perif_mmbi *mmbi; ++ struct ast2600_espi_perif *perif; ++ struct ast2600_espi *espi; + unsigned long vm_size; + pgprot_t prot; + -+ mmbi = container_of(fp->private_data, struct aspeed_espi_perif_mmbi, b2h_mdev); ++ mmbi = container_of(fp->private_data, struct ast2600_espi_perif_mmbi, b2h_mdev); + + perif = mmbi->perif; + -+ espi = container_of(perif, struct aspeed_espi, perif); ++ espi = container_of(perif, struct ast2600_espi, perif); + + vm_size = vma->vm_end - vma->vm_start; + prot = vma->vm_page_prot; @@ -77675,17 +69147,17 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + +static int ast2600_espi_mmbi_h2b_mmap(struct file *fp, struct vm_area_struct *vma) +{ -+ struct aspeed_espi_perif_mmbi *mmbi; -+ struct aspeed_espi_perif *perif; -+ 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; + -+ mmbi = container_of(fp->private_data, struct aspeed_espi_perif_mmbi, h2b_mdev); ++ mmbi = container_of(fp->private_data, struct ast2600_espi_perif_mmbi, h2b_mdev); + + perif = mmbi->perif; + -+ espi = container_of(perif, struct aspeed_espi, perif); ++ espi = container_of(perif, struct ast2600_espi, perif); + + vm_size = vma->vm_end - vma->vm_start; + prot = vma->vm_page_prot; @@ -77705,9 +69177,9 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + +static __poll_t ast2600_espi_mmbi_h2b_poll(struct file *fp, struct poll_table_struct *pt) +{ -+ struct aspeed_espi_perif_mmbi *mmbi; ++ struct ast2600_espi_perif_mmbi *mmbi; + -+ mmbi = container_of(fp->private_data, struct aspeed_espi_perif_mmbi, h2b_mdev); ++ mmbi = container_of(fp->private_data, struct ast2600_espi_perif_mmbi, h2b_mdev); + + poll_wait(fp, &mmbi->wq, pt); + @@ -77720,18 +69192,18 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as +} + +static long ast2600_espi_perif_pc_get_rx(struct file *fp, -+ struct aspeed_espi_perif *perif, ++ struct ast2600_espi_perif *perif, + struct aspeed_espi_ioc *ioc) +{ -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; ++ uint32_t reg, cyc, tag, len; ++ struct ast2600_espi *espi; + struct espi_comm_hdr *hdr; + unsigned long flags; -+ u32 pkt_len; -+ u8 *pkt; ++ uint32_t pkt_len; ++ uint8_t *pkt; + int i, rc; + -+ espi = container_of(perif, struct aspeed_espi, perif); ++ espi = container_of(perif, struct ast2600_espi, perif); + + if (fp->f_flags & O_NONBLOCK) { + if (!mutex_trylock(&perif->pc_rx_mtx)) @@ -77839,16 +69311,16 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as +} + +static long ast2600_espi_perif_pc_put_tx(struct file *fp, -+ struct aspeed_espi_perif *perif, ++ struct ast2600_espi_perif *perif, + struct aspeed_espi_ioc *ioc) +{ -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; ++ uint32_t reg, cyc, tag, len; ++ struct ast2600_espi *espi; + struct espi_comm_hdr *hdr; -+ u8 *pkt; ++ uint8_t *pkt; + int i, rc; + -+ espi = container_of(perif, struct aspeed_espi, perif); ++ espi = container_of(perif, struct ast2600_espi, perif); + + if (!mutex_trylock(&perif->pc_tx_mtx)) + return -EAGAIN; @@ -77906,16 +69378,16 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as +} + +static long ast2600_espi_perif_np_put_tx(struct file *fp, -+ struct aspeed_espi_perif *perif, ++ struct ast2600_espi_perif *perif, + struct aspeed_espi_ioc *ioc) +{ -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; ++ uint32_t reg, cyc, tag, len; ++ struct ast2600_espi *espi; + struct espi_comm_hdr *hdr; -+ u8 *pkt; ++ uint8_t *pkt; + int i, rc; + -+ espi = container_of(perif, struct aspeed_espi, perif); ++ espi = container_of(perif, struct ast2600_espi, perif); + + if (!mutex_trylock(&perif->np_tx_mtx)) + return -EAGAIN; @@ -77974,10 +69446,10 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + +static long ast2600_espi_perif_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ -+ struct aspeed_espi_perif *perif; ++ struct ast2600_espi_perif *perif; + struct aspeed_espi_ioc ioc; + -+ perif = container_of(fp->private_data, struct aspeed_espi_perif, mdev); ++ perif = container_of(fp->private_data, struct ast2600_espi_perif, mdev); + + if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) + return -EFAULT; @@ -78001,11 +69473,11 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + +static int ast2600_espi_perif_mmap(struct file *fp, struct vm_area_struct *vma) +{ -+ struct aspeed_espi_perif *perif; ++ struct ast2600_espi_perif *perif; + unsigned long vm_size; + pgprot_t vm_prot; + -+ perif = container_of(fp->private_data, struct aspeed_espi_perif, mdev); ++ perif = container_of(fp->private_data, struct ast2600_espi_perif, mdev); + if (!perif->mcyc.enable) + return -EPERM; + @@ -78044,14 +69516,14 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + +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; ++ 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 aspeed_espi *)arg; ++ espi = (struct ast2600_espi *)arg; + + perif = &espi->perif; + @@ -78065,7 +69537,7 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + + mmbi = &perif->mmbi.inst[i]; + -+ p = (u32 *)mmbi->h2b_virt; ++ 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); + @@ -78079,11 +69551,11 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + return IRQ_HANDLED; +} + -+static void ast2600_espi_perif_isr(struct aspeed_espi *espi) ++static void ast2600_espi_perif_isr(struct ast2600_espi *espi) +{ -+ struct aspeed_espi_perif *perif; ++ struct ast2600_espi_perif *perif; + unsigned long flags; -+ u32 sts; ++ uint32_t sts; + + perif = &espi->perif; + @@ -78100,10 +69572,10 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + } +} + -+static void ast2600_espi_perif_sw_reset(struct aspeed_espi *espi) ++static void ast2600_espi_perif_sw_reset(struct ast2600_espi *espi) +{ + struct device *dev; -+ u32 reg; ++ uint32_t reg; + + dev = espi->dev; + @@ -78127,11 +69599,11 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + writel(reg, espi->regs + ESPI_CTRL); +} + -+static void ast2600_espi_perif_reset(struct aspeed_espi *espi) ++static void ast2600_espi_perif_reset(struct ast2600_espi *espi) +{ -+ struct aspeed_espi_perif *perif; ++ struct ast2600_espi_perif *perif; + struct device *dev; -+ u32 reg, mask; ++ uint32_t reg, mask; + + dev = espi->dev; + @@ -78203,10 +69675,10 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + writel(reg, espi->regs + ESPI_CTRL); +} + -+int ast2600_espi_perif_probe(struct aspeed_espi *espi) ++static int ast2600_espi_perif_probe(struct ast2600_espi *espi) +{ -+ struct aspeed_espi_perif_mmbi *mmbi; -+ struct aspeed_espi_perif *perif; ++ struct ast2600_espi_perif_mmbi *mmbi; ++ struct ast2600_espi_perif *perif; + struct platform_device *pdev; + struct device *dev; + int i, rc; @@ -78225,7 +69697,7 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + + perif->mmbi.enable = of_property_read_bool(dev->of_node, "perif-mmbi-enable"); + if (perif->mmbi.enable) { -+ pdev = espi->pdev; ++ pdev = container_of(dev, struct platform_device, dev); + + perif->mmbi.irq = platform_get_irq(pdev, 1); + if (perif->mmbi.irq < 0) { @@ -78233,13 +69705,13 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + return -ENODEV; + } + -+ rc = of_property_read_u32(dev->of_node, "perif-mmbi-src-addr", (u32 *)&perif->mmbi.saddr); ++ 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", (u32 *)&perif->mmbi.inst_size); ++ 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; @@ -78253,8 +69725,6 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + 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]; + @@ -78296,13 +69766,13 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + return -EPERM; + } + -+ rc = of_property_read_u32(dev->of_node, "perif-mcyc-src-addr", (u32 *)&perif->mcyc.saddr); ++ 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", (u32 *)&perif->mcyc.size); ++ 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; @@ -78352,15 +69822,24 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + + 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; +} + -+int ast2600_espi_perif_remove(struct aspeed_espi *espi) ++static int ast2600_espi_perif_remove(struct ast2600_espi *espi) +{ -+ struct aspeed_espi_perif_mmbi *mmbi; -+ struct aspeed_espi_perif *perif; ++ struct ast2600_espi_perif_mmbi *mmbi; ++ struct ast2600_espi_perif *perif; + struct device *dev; -+ u32 reg; ++ uint32_t reg; + int i; + + dev = espi->dev; @@ -78420,13 +69899,13 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as +/* virtual wire channel (CH1) */ +static long ast2600_espi_vw_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ -+ struct aspeed_espi_vw *vw; -+ struct aspeed_espi *espi; -+ u32 gpio, hw_mode; ++ struct ast2600_espi_vw *vw; ++ struct ast2600_espi *espi; ++ uint32_t gpio, hw_mode; + -+ vw = container_of(fp->private_data, struct aspeed_espi_vw, mdev); -+ espi = container_of(vw, struct aspeed_espi, vw); -+ gpio = vw->gpio.val0; ++ 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; + + if (hw_mode) { @@ -78436,7 +69915,7 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + + switch (cmd) { + case ASPEED_ESPI_VW_GET_GPIO_VAL: -+ if (put_user(gpio, (u32 __user *)arg)) { ++ if (put_user(gpio, (uint32_t __user *)arg)) { + dev_err(espi->dev, "failed to get vGPIO value\n"); + return -EFAULT; + } @@ -78445,7 +69924,7 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + break; + + case ASPEED_ESPI_VW_PUT_GPIO_VAL: -+ if (get_user(gpio, (u32 __user *)arg)) { ++ if (get_user(gpio, (uint32_t __user *)arg)) { + dev_err(espi->dev, "failed to put vGPIO value\n"); + return -EFAULT; + } @@ -78466,17 +69945,17 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + .unlocked_ioctl = ast2600_espi_vw_ioctl, +}; + -+static void ast2600_espi_vw_isr(struct aspeed_espi *espi) ++static void ast2600_espi_vw_isr(struct ast2600_espi *espi) +{ -+ struct aspeed_espi_vw *vw; -+ u32 sts; ++ struct ast2600_espi_vw *vw; ++ uint32_t sts; + + vw = &espi->vw; + + sts = readl(espi->regs + ESPI_INT_STS); + + if (sts & ESPI_INT_STS_VW_GPIO) { -+ vw->gpio.val0 = readl(espi->regs + ESPI_VW_GPIO_VAL); ++ 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 */ @@ -78487,17 +69966,17 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + } +} + -+static void ast2600_espi_vw_reset(struct aspeed_espi *espi) ++static void ast2600_espi_vw_reset(struct ast2600_espi *espi) +{ -+ u32 reg; -+ struct aspeed_espi_vw *vw = &espi->vw; ++ 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.dir0, espi->regs + ESPI_VW_GPIO_DIR); ++ writel(vw->gpio.dir, espi->regs + ESPI_VW_GPIO_DIR); + -+ vw->gpio.val0 = readl(espi->regs + ESPI_VW_GPIO_VAL); ++ vw->gpio.val = readl(espi->regs + ESPI_VW_GPIO_VAL); + + reg = readl(espi->regs + ESPI_CTRL2) & ~(ESPI_CTRL2_VW_TX_SORT); + writel(reg, espi->regs + ESPI_CTRL2); @@ -78521,14 +70000,14 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + writel(0x1, espi->regs + ESPI_VW_SYSEVT1_INT_T0); +} + -+int ast2600_espi_vw_probe(struct aspeed_espi *espi) ++static int ast2600_espi_vw_probe(struct ast2600_espi *espi) +{ + int rc; + struct device *dev = espi->dev; -+ struct aspeed_espi_vw *vw = &espi->vw; ++ 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.dir0); ++ of_property_read_u32(dev->of_node, "vw-gpio-direction", &vw->gpio.dir); + + vw->mdev.parent = dev; + vw->mdev.minor = MISC_DYNAMIC_MINOR; @@ -78545,9 +70024,9 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + return 0; +} + -+int ast2600_espi_vw_remove(struct aspeed_espi *espi) ++static int ast2600_espi_vw_remove(struct ast2600_espi *espi) +{ -+ struct aspeed_espi_vw *vw; ++ struct ast2600_espi_vw *vw; + + vw = &espi->vw; + @@ -78560,24 +70039,22 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + +/* out-of-band channel (CH2) */ +static long ast2600_espi_oob_dma_get_rx(struct file *fp, -+ struct aspeed_espi_oob *oob, ++ struct ast2600_espi_oob *oob, + struct aspeed_espi_ioc *ioc) +{ + struct ast2600_espi_oob_dma_rx_desc *d; -+ struct ast2600_espi_oob_dma_rx_desc *rx_descs; -+ struct aspeed_espi *espi; ++ struct ast2600_espi *espi; + struct espi_comm_hdr *hdr; -+ u32 wptr, pkt_len; ++ uint32_t wptr, pkt_len; + unsigned long flags; -+ u8 *pkt; ++ uint8_t *pkt; + int rc; + -+ espi = container_of(oob, struct aspeed_espi, oob); ++ espi = container_of(oob, struct ast2600_espi, oob); + + wptr = FIELD_PREP(ESPI_OOB_RX_DESC_WPTR_WP, readl(espi->regs + ESPI_OOB_RX_DESC_WPTR)); + -+ rx_descs = (struct ast2600_espi_oob_dma_rx_desc *)oob->dma.rxd_virt; -+ d = &rx_descs[wptr]; ++ d = &oob->dma.rxd_virt[wptr]; + + if (!d->dirty) + return -EFAULT; @@ -78608,49 +70085,485 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + /* make current descriptor available again */ + d->dirty = 0; + -+ wptr = (wptr + 1) % OOB_DMA_DESC_NUM; -+ writel(wptr | ESPI_OOB_RX_DESC_WPTR_RECV_EN, espi->regs + ESPI_OOB_RX_DESC_WPTR); ++ wptr = (wptr + 1) % OOB_DMA_DESC_NUM; ++ 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; ++ ++ 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 ast2600_espi_oob *oob, ++ 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; ++ ++ espi = container_of(oob, struct ast2600_espi, oob); ++ ++ if (fp->f_flags & O_NONBLOCK) { ++ if (!mutex_trylock(&oob->rx_mtx)) ++ return -EAGAIN; ++ ++ if (!oob->rx_ready) { ++ rc = -ENODATA; ++ goto unlock_mtx_n_out; ++ } ++ } else { ++ mutex_lock(&oob->rx_mtx); ++ ++ if (!oob->rx_ready) { ++ rc = wait_event_interruptible(oob->wq, oob->rx_ready); ++ if (rc == -ERESTARTSYS) { ++ rc = -EINTR; ++ goto unlock_mtx_n_out; ++ } ++ } ++ } ++ ++ 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); ++ ++ /* ++ * 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); ++ ++ 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; ++ ++ for (i = sizeof(*hdr); i < pkt_len; ++i) ++ pkt[i] = readl(espi->regs + ESPI_OOB_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); ++ ++ writel(ESPI_OOB_RX_CTRL_SERV_PEND, espi->regs + ESPI_OOB_RX_CTRL); ++ oob->rx_ready = 0; ++ ++ spin_unlock_irqrestore(&oob->lock, flags); ++ ++ rc = 0; ++ ++free_n_out: ++ 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); ++ ++ return rc; ++} ++ ++static long ast2600_espi_oob_put_tx(struct file *fp, ++ struct ast2600_espi_oob *oob, ++ 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(oob, struct ast2600_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 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; + -+ /* set ready flag base on the next RX descriptor */ -+ oob->rx_ready = rx_descs[wptr].dirty; ++ writel(ESPI_INT_EN_OOB, espi->regs + ESPI_INT_EN_CLR); + -+ spin_unlock_irqrestore(&oob->lock, flags); ++ 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); + -+ rc = 0; ++ 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); ++ } + -+free_n_out: -+ vfree(pkt); ++ mutex_destroy(&oob->tx_mtx); ++ mutex_destroy(&oob->rx_mtx); + -+ return rc; ++ misc_deregister(&oob->mdev); ++ ++ return 0; +} + -+static long ast2600_espi_oob_get_rx(struct file *fp, -+ struct aspeed_espi_oob *oob, -+ struct aspeed_espi_ioc *ioc) ++/* flash channel (CH3) */ ++static long ast2600_espi_flash_get_rx(struct file *fp, ++ struct ast2600_espi_flash *flash, ++ struct aspeed_espi_ioc *ioc) +{ -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; ++ uint32_t reg, cyc, tag, len; ++ struct ast2600_espi *espi; + struct espi_comm_hdr *hdr; + unsigned long flags; -+ u32 pkt_len; -+ u8 *pkt; ++ uint32_t pkt_len; ++ uint8_t *pkt; + int i, rc; + -+ espi = container_of(oob, struct aspeed_espi, oob); ++ rc = 0; ++ ++ espi = container_of(flash, struct ast2600_espi, flash); + + if (fp->f_flags & O_NONBLOCK) { -+ if (!mutex_trylock(&oob->rx_mtx)) ++ if (!mutex_trylock(&flash->rx_mtx)) + return -EAGAIN; + -+ if (!oob->rx_ready) { ++ if (!flash->rx_ready) { + rc = -ENODATA; + goto unlock_mtx_n_out; + } + } else { -+ mutex_lock(&oob->rx_mtx); ++ mutex_lock(&flash->rx_mtx); + -+ if (!oob->rx_ready) { -+ rc = wait_event_interruptible(oob->wq, oob->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; @@ -78658,26 +70571,44 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + } + } + -+ 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_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. + */ -+ pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + sizeof(struct espi_comm_hdr); ++ 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; @@ -78696,20 +70627,24 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + 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 (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(&oob->lock, flags); ++ spin_lock_irqsave(&flash->lock, flags); + -+ writel(ESPI_OOB_RX_CTRL_SERV_PEND, espi->regs + ESPI_OOB_RX_CTRL); -+ oob->rx_ready = 0; ++ writel(ESPI_FLASH_RX_CTRL_SERV_PEND, espi->regs + ESPI_FLASH_RX_CTRL); ++ flash->rx_ready = 0; + -+ spin_unlock_irqrestore(&oob->lock, flags); ++ spin_unlock_irqrestore(&flash->lock, flags); + + rc = 0; + @@ -78717,100 +70652,32 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + 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 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; -+ -+ espi = container_of(oob, struct aspeed_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; -+ } -+ -+ 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; -+ -+ 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(&flash->rx_mtx); + + return rc; +} + -+static long ast2600_espi_oob_put_tx(struct file *fp, -+ struct aspeed_espi_oob *oob, -+ struct aspeed_espi_ioc *ioc) ++static long ast2600_espi_flash_put_tx(struct file *fp, ++ struct ast2600_espi_flash *flash, ++ struct aspeed_espi_ioc *ioc) +{ -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; ++ uint32_t reg, cyc, tag, len; ++ struct ast2600_espi *espi; + struct espi_comm_hdr *hdr; -+ u8 *pkt; ++ uint8_t *pkt; + int i, rc; + -+ espi = container_of(oob, struct aspeed_espi, oob); ++ espi = container_of(flash, struct ast2600_espi, flash); + -+ if (!mutex_trylock(&oob->tx_mtx)) ++ if (!mutex_trylock(&flash->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_FLASH_TX_CTRL); ++ if (reg & ESPI_FLASH_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; @@ -78828,18 +70695,23 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + * 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); ++ 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; + @@ -78847,17 +70719,17 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + vfree(pkt); + +unlock_mtx_n_out: -+ mutex_unlock(&oob->tx_mtx); ++ mutex_unlock(&flash->tx_mtx); + + return rc; +} + -+static long ast2600_espi_oob_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 aspeed_espi_oob *oob; ++ struct ast2600_espi_flash *flash; + struct aspeed_espi_ioc ioc; + -+ oob = container_of(fp->private_data, struct aspeed_espi_oob, mdev); ++ flash = container_of(fp->private_data, struct ast2600_espi_flash, mdev); + + if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) + return -EFAULT; @@ -78866,981 +70738,1337 @@ diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/espi/as + 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); ++ 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; + }; + + return -EINVAL; +} + -+static const struct file_operations ast2600_espi_oob_fops = { ++static const struct file_operations ast2600_espi_flash_fops = { + .owner = THIS_MODULE, -+ .unlocked_ioctl = ast2600_espi_oob_ioctl, ++ .unlocked_ioctl = ast2600_espi_flash_ioctl, +}; + -+static void ast2600_espi_oob_isr(struct aspeed_espi *espi) ++static void ast2600_espi_flash_isr(struct ast2600_espi *espi) +{ -+ struct aspeed_espi_oob *oob; ++ struct ast2600_espi_flash *flash; + unsigned long flags; -+ u32 sts; ++ uint32_t 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) { ++ writel(ESPI_INT_STS_FLASH_RX_CMPLT, espi->regs + ESPI_INT_STS); + -+ spin_lock_irqsave(&oob->lock, flags); -+ oob->rx_ready = true; -+ spin_unlock_irqrestore(&oob->lock, flags); ++ spin_lock_irqsave(&flash->lock, flags); ++ flash->rx_ready = true; ++ spin_unlock_irqrestore(&flash->lock, flags); + -+ wake_up_interruptible(&oob->wq); ++ wake_up_interruptible(&flash->wq); + } +} + -+static void ast2600_espi_oob_reset(struct aspeed_espi *espi) ++static void ast2600_espi_flash_reset(struct ast2600_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; ++ struct ast2600_espi_flash *flash; ++ uint32_t reg; + -+ writel(ESPI_INT_EN_OOB, espi->regs + ESPI_INT_EN_CLR); -+ writel(ESPI_INT_STS_OOB, espi->regs + ESPI_INT_STS); ++ flash = &espi->flash; ++ ++ 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_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); + -+ 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; -+ } ++ 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); + -+ 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); ++ 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); ++ } + -+ 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); ++ 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); -+ -+ /* 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); ++ writel(ESPI_INT_EN_FLASH_RX_CMPLT, 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); +} + -+int ast2600_espi_oob_probe(struct aspeed_espi *espi) ++static int ast2600_espi_flash_probe(struct ast2600_espi *espi) +{ -+ struct aspeed_espi_oob *oob; ++ struct ast2600_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.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; ++ flash->safs.mode = SAFS_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)) { ++ dev_err(dev, "cannot get 16MB-aligned SAFS target address\n"); ++ return -ENODEV; + } -+ 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; ++ ++ 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; + } ++ } + -+ 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"); ++ 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_DESC_NUM, &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 = &ast2600_espi_oob_fops; -+ rc = misc_register(&oob->mdev); -+ if (rc) { -+ dev_err(dev, "cannot register device %s\n", oob->mdev.name); -+ return rc; -+ } ++ 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; ++ } ++ ++ ast2600_espi_flash_reset(espi); ++ ++ return 0; ++} ++ ++static int ast2600_espi_flash_remove(struct ast2600_espi *espi) ++{ ++ struct ast2600_espi_flash *flash; ++ struct device *dev; ++ uint32_t reg; ++ ++ dev = espi->dev; ++ ++ flash = &espi->flash; ++ ++ writel(ESPI_INT_EN_FLASH, espi->regs + ESPI_INT_EN_CLR); ++ ++ 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 */ ++static irqreturn_t ast2600_espi_isr(int irq, void *arg) ++{ ++ struct ast2600_espi *espi; ++ uint32_t sts; ++ ++ espi = (struct ast2600_espi *)arg; ++ ++ sts = readl(espi->regs + ESPI_INT_STS); ++ if (!sts) ++ return IRQ_NONE; ++ ++ if (sts & ESPI_INT_STS_PERIF) ++ ast2600_espi_perif_isr(espi); ++ ++ if (sts & ESPI_INT_STS_VW) ++ ast2600_espi_vw_isr(espi); ++ ++ if (sts & ESPI_INT_STS_OOB) ++ ast2600_espi_oob_isr(espi); ++ ++ if (sts & ESPI_INT_STS_FLASH) ++ ast2600_espi_flash_isr(espi); ++ ++ 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); ++ ++ 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); ++ ++ /* re-enable eSPI_RESET# interrupt */ ++ writel(ESPI_INT_EN_RST_DEASSERT, espi->regs + ESPI_INT_EN); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static int ast2600_espi_probe(struct platform_device *pdev) ++{ ++ 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; ++ } ++ ++ 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) ++{ ++ 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); + -+ ast2600_espi_oob_reset(espi); ++ rc = ast2600_espi_oob_remove(espi); ++ if (rc) ++ dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); + -+ return 0; ++ rc = ast2600_espi_flash_remove(espi); ++ if (rc) ++ dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); +} + -+int ast2600_espi_oob_remove(struct aspeed_espi *espi) -+{ -+ struct aspeed_espi_oob *oob; -+ struct device *dev; -+ u32 reg; ++static const struct of_device_id ast2600_espi_of_matches[] = { ++ { .compatible = "aspeed,ast2600-espi" }, ++ { }, ++}; + -+ dev = espi->dev; ++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, ++}; + -+ oob = &espi->oob; ++module_platform_driver(ast2600_espi_driver); + -+ writel(ESPI_INT_EN_OOB, espi->regs + ESPI_INT_EN_CLR); ++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_ + -+ 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); ++#include ++#include "aspeed-espi-comm.h" + -+ 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); ++/* 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)) + -+ 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); -+ } ++/* 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) + -+ mutex_destroy(&oob->tx_mtx); -+ mutex_destroy(&oob->rx_mtx); ++#define ESPI_INT_EN_VW \ ++ (ESPI_INT_EN_VW_SYSEVT1 | \ ++ ESPI_INT_EN_VW_GPIO | \ ++ ESPI_INT_EN_VW_SYSEVT) + -+ misc_deregister(&oob->mdev); ++#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) + -+ return 0; -+} ++#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) + -+/* flash channel (CH3) */ -+static long ast2600_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; ++/* 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) + -+ rc = 0; ++#define ESPI_INT_STS_VW \ ++ (ESPI_INT_STS_VW_SYSEVT1 | \ ++ ESPI_INT_STS_VW_GPIO | \ ++ ESPI_INT_STS_VW_SYSEVT) + -+ espi = container_of(flash, struct aspeed_espi, flash); ++#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(&flash->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 (!flash->rx_ready) { -+ rc = -ENODATA; -+ goto unlock_mtx_n_out; -+ } -+ } else { -+ mutex_lock(&flash->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 (!flash->rx_ready) { -+ rc = wait_event_interruptible(flash->wq, flash->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, ++}; + -+ /* -+ * 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); ++#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. ++ */ + -+ /* -+ * 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; -+ } ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ if (ioc->pkt_len < pkt_len) { -+ rc = -EINVAL; -+ goto unlock_mtx_n_out; -+ } ++#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 + -+ 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; ++}; + -+ 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; -+ } ++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; ++ ++ val = readl(ctx->reg_base + reg); ++ // printk("read:reg = 0x%08x, val = 0x%08x\n", reg, val); ++ return val; ++} ++ ++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); ++} ++ ++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; ++} + -+ 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); ++static void wait_complete(struct aspeed_otp *ctx) ++{ ++ int reg; ++ int i = 0; + -+ rc = 0; ++ do { ++ reg = aspeed_otp_read(ctx, OTP_STATUS); ++ if ((reg & 0x6) == 0x6) ++ i++; ++ } while (i != 2); ++} + -+free_n_out: -+ vfree(pkt); ++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); ++} + -+unlock_mtx_n_out: -+ mutex_unlock(&flash->rx_mtx); ++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; ++ } ++ } + -+ return rc; ++ wait_complete(ctx); +} + -+static long ast2600_espi_flash_put_tx(struct file *fp, -+ struct aspeed_espi_flash *flash, -+ struct aspeed_espi_ioc *ioc) ++static int verify_bit(struct aspeed_otp *ctx, u32 otp_addr, int bit_offset, int value) +{ -+ 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); ++ u32 ret[2]; + -+ if (!mutex_trylock(&flash->tx_mtx)) -+ return -EAGAIN; ++ 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 + -+ reg = readl(espi->regs + ESPI_FLASH_TX_CTRL); -+ if (reg & ESPI_FLASH_TX_CTRL_TRIG_PEND) { -+ rc = -EBUSY; -+ goto unlock_mtx_n_out; -+ } ++ 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); + -+ pkt = vmalloc(ioc->pkt_len); -+ if (!pkt) { -+ rc = -ENOMEM; -+ goto unlock_mtx_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; + } ++} + -+ hdr = (struct espi_comm_hdr *)pkt; ++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); ++} + -+ if (copy_from_user(pkt, (void __user *)ioc->pkt, ioc->pkt_len)) { -+ rc = -EFAULT; -+ goto free_n_out; -+ } ++static void _otp_prog_bit(struct aspeed_otp *ctx, u32 value, u32 prog_address, u32 bit_offset) ++{ ++ int prog_bit; + -+ /* -+ * 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(); ++ if (prog_address % 2 == 0) { ++ if (value) ++ prog_bit = ~(0x1 << bit_offset); ++ else ++ return; + } else { -+ for (i = sizeof(*hdr); i < ioc->pkt_len; ++i) -+ writel(pkt[i], espi->regs + ESPI_FLASH_TX_DATA); ++ 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); ++} + -+ cyc = hdr->cyc; -+ tag = hdr->tag; -+ len = (hdr->len_h << 8) | (hdr->len_l & 0xff); ++static int otp_prog_bit(struct aspeed_otp *ctx, u32 value, u32 prog_address, u32 bit_offset) ++{ ++ int pass; ++ int i; + -+ 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); ++ otp_soak(ctx, 1); ++ _otp_prog_bit(ctx, value, prog_address, bit_offset); ++ pass = 0; + -+ rc = 0; ++ 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; ++} + -+free_n_out: -+ vfree(pkt); ++static void otp_read_conf_dw(struct aspeed_otp *ctx, u32 offset, u32 *buf) ++{ ++ u32 config_offset; + -+unlock_mtx_n_out: -+ mutex_unlock(&flash->tx_mtx); ++ config_offset = 0x800; ++ config_offset |= (offset / 8) * 0x200; ++ config_offset |= (offset % 8) * 0x2; + -+ return rc; ++ 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); +} + -+static long ast2600_espi_flash_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) ++static void otp_read_conf(struct aspeed_otp *ctx, u32 offset, u32 len) +{ -+ struct aspeed_espi_flash *flash; -+ struct aspeed_espi_ioc ioc; ++ int i, j; + -+ flash = container_of(fp->private_data, struct aspeed_espi_flash, mdev); ++ otp_soak(ctx, 0); ++ for (i = offset, j = 0; j < len; i++, j++) ++ otp_read_conf_dw(ctx, i, &ctx->data[j]); ++} + -+ if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) -+ return -EFAULT; ++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); ++} + -+ if (ioc.pkt_len > ESPI_MAX_PKT_LEN) -+ return -EINVAL; ++static void otp_read_data(struct aspeed_otp *ctx, u32 offset, u32 len) ++{ ++ int i, j; ++ u32 ret[2]; + -+ 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); -+ default: -+ break; -+ }; ++ otp_soak(ctx, 0); + -+ return -EINVAL; ++ 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]); +} + -+static const struct file_operations ast2600_espi_flash_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = ast2600_espi_flash_ioctl, -+}; -+ -+static void ast2600_espi_flash_isr(struct aspeed_espi *espi) ++static int otp_prog_data(struct aspeed_otp *ctx, u32 value, u32 dw_offset, u32 bit_offset) +{ -+ struct aspeed_espi_flash *flash; -+ unsigned long flags; -+ u32 sts; -+ -+ flash = &espi->flash; -+ -+ sts = readl(espi->regs + ESPI_INT_STS); ++ u32 read[2]; ++ int otp_bit; + -+ if (sts & ESPI_INT_STS_FLASH_RX_CMPLT) { -+ writel(ESPI_INT_STS_FLASH_RX_CMPLT, espi->regs + ESPI_INT_STS); ++ if (dw_offset % 2 == 0) { ++ otp_read_data_2dw(ctx, dw_offset, read); ++ otp_bit = (read[0] >> bit_offset) & 0x1; + -+ spin_lock_irqsave(&flash->lock, flags); -+ flash->rx_ready = true; -+ spin_unlock_irqrestore(&flash->lock, flags); ++ 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; + -+ wake_up_interruptible(&flash->wq); ++ 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; ++ } ++ ++ return otp_prog_bit(ctx, value, dw_offset, bit_offset); +} + -+static void ast2600_espi_flash_reset(struct aspeed_espi *espi) ++static int otp_prog_conf(struct aspeed_otp *ctx, u32 value, u32 dw_offset, u32 bit_offset) +{ -+ struct aspeed_espi_flash *flash; -+ u32 reg; -+ -+ flash = &espi->flash; ++ u32 read; ++ u32 prog_address = 0; ++ int otp_bit; + -+ writel(ESPI_INT_EN_FLASH, espi->regs + ESPI_INT_EN_CLR); -+ writel(ESPI_INT_STS_FLASH, espi->regs + ESPI_INT_STS); ++ otp_read_conf_dw(ctx, dw_offset, &read); + -+ 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); ++ 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; ++ } + -+ udelay(1); ++ return otp_prog_bit(ctx, value, prog_address, bit_offset); ++} + -+ reg |= (ESPI_CTRL_FLASH_TX_SW_RST | ESPI_CTRL_FLASH_RX_SW_RST); -+ writel(reg, espi->regs + ESPI_CTRL); ++struct aspeed_otp *glob_ctx; + -+ 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); ++void otp_read_data_buf(u32 offset, u32 *buf, u32 len) ++{ ++ int i, j; ++ u32 ret[2]; + -+ 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); -+ } ++ aspeed_otp_write(glob_ctx, OTP_PASSWD, OTP_PROTECT_KEY); + -+ 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); ++ otp_soak(glob_ctx, 0); + -+ reg = readl(espi->regs + ESPI_CTRL) -+ | ESPI_CTRL_FLASH_TX_DMA_EN -+ | ESPI_CTRL_FLASH_RX_DMA_EN; -+ writel(reg, espi->regs + ESPI_CTRL); ++ i = offset; ++ j = 0; ++ if (offset % 2) { ++ otp_read_data_2dw(glob_ctx, i - 1, ret); ++ buf[0] = ret[1]; ++ i++; ++ j++; + } -+ -+ 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); ++ 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); + -+int ast2600_espi_flash_probe(struct aspeed_espi *espi) ++void otp_read_conf_buf(u32 offset, u32 *buf, u32 len) +{ -+ struct aspeed_espi_flash *flash; -+ struct device *dev; -+ int rc; ++ int i, j; + -+ dev = espi->dev; ++ 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); + -+ flash = &espi->flash; ++static long 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_read xfer; ++ struct otp_prog prog; ++ u32 reg_read[2]; ++ int ret = 0; + -+ init_waitqueue_head(&flash->wq); ++ 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; ++ } + -+ spin_lock_init(&flash->lock); ++ 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); + -+ mutex_init(&flash->tx_mtx); -+ mutex_init(&flash->rx_mtx); ++ 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; ++ } + -+ flash->edaf.mode = EDAF_MODE_HW; ++ 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); + -+ 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; ++ 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; + } -+ -+ 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 (prog.dw_offset >= 0x800) { ++ pr_err("out of range"); ++ 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; ++ 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; + } -+ -+ 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; ++ 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; + } -+ -+ 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; -+ } -+ -+ ast2600_espi_flash_reset(espi); -+ -+ return 0; ++ return ret; +} + -+int ast2600_espi_flash_remove(struct aspeed_espi *espi) ++static int otp_open(struct inode *inode, struct file *file) +{ -+ struct aspeed_espi_flash *flash; -+ struct device *dev; -+ u32 reg; -+ -+ dev = espi->dev; -+ -+ flash = &espi->flash; -+ -+ writel(ESPI_INT_EN_FLASH, espi->regs + ESPI_INT_EN_CLR); -+ -+ 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); ++ struct miscdevice *c = file->private_data; ++ struct aspeed_otp *ctx = container_of(c, struct aspeed_otp, miscdev); + -+ 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); ++ spin_lock(&otp_state_lock); ++ ++ if (ctx->is_open) { ++ spin_unlock(&otp_state_lock); ++ return -EBUSY; + } + -+ mutex_destroy(&flash->tx_mtx); -+ mutex_destroy(&flash->rx_mtx); ++ ctx->is_open = true; + -+ misc_deregister(&flash->mdev); ++ spin_unlock(&otp_state_lock); + + return 0; +} + -+/* global control */ -+irqreturn_t ast2600_espi_isr(int irq, void *arg) ++static int otp_release(struct inode *inode, struct file *file) +{ -+ 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) -+ ast2600_espi_perif_isr(espi); -+ -+ if (sts & ESPI_INT_STS_VW) -+ ast2600_espi_vw_isr(espi); ++ struct miscdevice *c = file->private_data; ++ struct aspeed_otp *ctx = container_of(c, struct aspeed_otp, miscdev); + -+ if (sts & ESPI_INT_STS_OOB) -+ ast2600_espi_oob_isr(espi); ++ spin_lock(&otp_state_lock); + -+ if (sts & ESPI_INT_STS_FLASH) -+ ast2600_espi_flash_isr(espi); ++ ctx->is_open = false; + -+ 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); ++ spin_unlock(&otp_state_lock); + -+ 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); ++ return 0; ++} + -+ /* re-enable eSPI_RESET# interrupt */ -+ writel(ESPI_INT_EN_RST_DEASSERT, espi->regs + ESPI_INT_EN); -+ } ++static const struct file_operations otp_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = otp_ioctl, ++ .open = otp_open, ++ .release = otp_release, ++}; + -+ return IRQ_HANDLED; -+} ++static const struct of_device_id aspeed_otp_of_matches[] = { ++ { .compatible = "aspeed,ast2600-sbc" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, aspeed_otp_of_matches); + -+void ast2600_espi_pre_init(struct aspeed_espi *espi) ++static int aspeed_otp_probe(struct platform_device *pdev) +{ -+ writel(ESPI_INT_EN_RST_DEASSERT, espi->regs + ESPI_INT_EN_CLR); -+} ++ struct device *dev = &pdev->dev; ++ struct regmap *scu; ++ struct aspeed_otp *priv; ++ struct resource *res; ++ u32 revid0, revid1; ++ int rc; + -+void ast2600_espi_post_init(struct aspeed_espi *espi) -+{ -+ writel(ESPI_INT_EN_RST_DEASSERT, espi->regs + ESPI_INT_EN); -+} ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ glob_ctx = priv; ++ if (!priv) ++ return -ENOMEM; + -+void ast2600_espi_deinit(struct aspeed_espi *espi) -+{ -+ 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-04-08 18:03:48.313705265 +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_ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "cannot get IORESOURCE_MEM\n"); ++ return -ENOENT; ++ } + -+#include -+#include ++ priv->reg_base = devm_ioremap_resource(&pdev->dev, res); ++ if (!priv->reg_base) ++ return -EIO; + -+#include "aspeed-espi.h" ++ 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); ++ } + -+/* 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)) ++ regmap_read(scu, ASPEED_REVISION_ID0, &revid0); ++ regmap_read(scu, ASPEED_REVISION_ID1, &revid1); + -+/* 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) ++ priv->otp_ver = chip_version(revid0, revid1); + -+#define ESPI_INT_EN_VW \ -+ (ESPI_INT_EN_VW_SYSEVT1 | \ -+ ESPI_INT_EN_VW_GPIO | \ -+ ESPI_INT_EN_VW_SYSEVT) ++ if (priv->otp_ver == -1) { ++ dev_err(dev, "invalid SCU\n"); ++ return -EINVAL; ++ } + -+#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) ++ priv->data = kmalloc(8192, GFP_KERNEL); ++ if (!priv->data) ++ return -ENOMEM; + -+#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) ++ dev_set_drvdata(dev, priv); + -+/* 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) ++ /* Set up the miscdevice */ ++ priv->miscdev.minor = MISC_DYNAMIC_MINOR; ++ priv->miscdev.name = "aspeed-otp"; ++ priv->miscdev.fops = &otp_fops; + -+#define ESPI_INT_STS_VW \ -+ (ESPI_INT_STS_VW_SYSEVT1 | \ -+ ESPI_INT_STS_VW_GPIO | \ -+ ESPI_INT_STS_VW_SYSEVT) ++ /* Register the device */ ++ rc = misc_register(&priv->miscdev); ++ if (rc) { ++ dev_err(dev, "Unable to register device\n"); ++ return rc; ++ } + -+#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) ++ return 0; ++} + -+#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) ++static void aspeed_otp_remove(struct platform_device *pdev) ++{ ++ struct aspeed_otp *ctx = dev_get_drvdata(&pdev->dev); + ++ kfree(ctx->data); ++ misc_deregister(&ctx->miscdev); ++} + -+/* 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, ++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, ++ }, +}; + -+/* 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-04-08 18:03:48.313705265 +0000 -@@ -0,0 +1,2180 @@ ++module_platform_driver(aspeed_otp_driver); ++ ++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 "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 @@ -79863,13 +72091,14 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as +#include + +#include "ast2700-espi.h" -+#include "aspeed-espi-comm.h" -+#include "aspeed-espi.h" ++ ++#define DEVICE_NAME "aspeed-espi" + +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 @@ -79877,20 +72106,178 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + +#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 aspeed_espi_perif_mmbi *mmbi; -+ struct aspeed_espi_perif *perif; -+ 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; + -+ mmbi = container_of(fp->private_data, struct aspeed_espi_perif_mmbi, b2h_mdev); ++ mmbi = container_of(fp->private_data, struct ast2700_espi_perif_mmbi, b2h_mdev); + + perif = mmbi->perif; + -+ espi = container_of(perif, struct aspeed_espi, perif); ++ espi = container_of(perif, struct ast2700_espi, perif); ++ + vm_size = vma->vm_end - vma->vm_start; + prot = vma->vm_page_prot; + @@ -79909,17 +72296,17 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + +static int ast2700_espi_mmbi_h2b_mmap(struct file *fp, struct vm_area_struct *vma) +{ -+ struct aspeed_espi_perif_mmbi *mmbi; -+ struct aspeed_espi_perif *perif; -+ 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; + -+ mmbi = container_of(fp->private_data, struct aspeed_espi_perif_mmbi, h2b_mdev); ++ mmbi = container_of(fp->private_data, struct ast2700_espi_perif_mmbi, h2b_mdev); + + perif = mmbi->perif; + -+ espi = container_of(perif, struct aspeed_espi, perif); ++ espi = container_of(perif, struct ast2700_espi, perif); + + vm_size = vma->vm_end - vma->vm_start; + prot = vma->vm_page_prot; @@ -79939,9 +72326,9 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + +static __poll_t ast2700_espi_mmbi_h2b_poll(struct file *fp, struct poll_table_struct *pt) +{ -+ struct aspeed_espi_perif_mmbi *mmbi; ++ struct ast2700_espi_perif_mmbi *mmbi; + -+ mmbi = container_of(fp->private_data, struct aspeed_espi_perif_mmbi, h2b_mdev); ++ mmbi = container_of(fp->private_data, struct ast2700_espi_perif_mmbi, h2b_mdev); + + poll_wait(fp, &mmbi->wq, pt); + @@ -79954,18 +72341,18 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as +} + +static long ast2700_espi_perif_pc_get_rx(struct file *fp, -+ struct aspeed_espi_perif *perif, ++ struct ast2700_espi_perif *perif, + struct aspeed_espi_ioc *ioc) +{ -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; ++ uint32_t reg, cyc, tag, len; ++ struct ast2700_espi *espi; + struct espi_comm_hdr *hdr; + unsigned long flags; -+ u32 pkt_len; -+ u8 *pkt; ++ uint32_t pkt_len; ++ uint8_t *pkt; + int i, rc; + -+ espi = container_of(perif, struct aspeed_espi, perif); ++ espi = container_of(perif, struct ast2700_espi, perif); + + if (fp->f_flags & O_NONBLOCK) { + if (!mutex_trylock(&perif->pc_rx_mtx)) @@ -80073,16 +72460,16 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as +} + +static long ast2700_espi_perif_pc_put_tx(struct file *fp, -+ struct aspeed_espi_perif *perif, ++ struct ast2700_espi_perif *perif, + struct aspeed_espi_ioc *ioc) +{ -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; ++ uint32_t reg, cyc, tag, len; ++ struct ast2700_espi *espi; + struct espi_comm_hdr *hdr; -+ u8 *pkt; ++ uint8_t *pkt; + int i, rc; + -+ espi = container_of(perif, struct aspeed_espi, perif); ++ espi = container_of(perif, struct ast2700_espi, perif); + + if (!mutex_trylock(&perif->pc_tx_mtx)) + return -EAGAIN; @@ -80140,16 +72527,16 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as +} + +static long ast2700_espi_perif_np_put_tx(struct file *fp, -+ struct aspeed_espi_perif *perif, ++ struct ast2700_espi_perif *perif, + struct aspeed_espi_ioc *ioc) +{ -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; ++ uint32_t reg, cyc, tag, len; ++ struct ast2700_espi *espi; + struct espi_comm_hdr *hdr; -+ u8 *pkt; ++ uint8_t *pkt; + int i, rc; + -+ espi = container_of(perif, struct aspeed_espi, perif); ++ espi = container_of(perif, struct ast2700_espi, perif); + + if (!mutex_trylock(&perif->np_tx_mtx)) + return -EAGAIN; @@ -80208,10 +72595,10 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + +static long ast2700_espi_perif_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ -+ struct aspeed_espi_perif *perif; ++ struct ast2700_espi_perif *perif; + struct aspeed_espi_ioc ioc; + -+ perif = container_of(fp->private_data, struct aspeed_espi_perif, mdev); ++ perif = container_of(fp->private_data, struct ast2700_espi_perif, mdev); + + if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) + return -EFAULT; @@ -80235,11 +72622,11 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + +static int ast2700_espi_perif_mmap(struct file *fp, struct vm_area_struct *vma) +{ -+ struct aspeed_espi_perif *perif; ++ struct ast2700_espi_perif *perif; + unsigned long vm_size; + pgprot_t vm_prot; + -+ perif = container_of(fp->private_data, struct aspeed_espi_perif, mdev); ++ perif = container_of(fp->private_data, struct ast2700_espi_perif, mdev); + if (!perif->mcyc.enable) + return -EPERM; + @@ -80278,14 +72665,14 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + +static irqreturn_t ast2700_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; ++ 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 aspeed_espi *)arg; ++ espi = (struct ast2700_espi *)arg; + + perif = &espi->perif; + @@ -80299,7 +72686,7 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + + mmbi = &perif->mmbi.inst[i]; + -+ p = (u32 *)mmbi->h2b_virt; ++ 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); + @@ -80313,11 +72700,11 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + return IRQ_HANDLED; +} + -+static void ast2700_espi_perif_isr(struct aspeed_espi *espi) ++static void ast2700_espi_perif_isr(struct ast2700_espi *espi) +{ -+ struct aspeed_espi_perif *perif; ++ struct ast2700_espi_perif *perif; + unsigned long flags; -+ u32 sts; ++ uint32_t sts; + + perif = &espi->perif; + @@ -80334,10 +72721,10 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + } +} + -+static void ast2700_espi_perif_sw_reset(struct aspeed_espi *espi) ++static void ast2700_espi_perif_sw_reset(struct ast2700_espi *espi) +{ + struct device *dev; -+ u32 reg; ++ uint32_t reg; + + dev = espi->dev; + @@ -80361,12 +72748,12 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + writel(reg, espi->regs + ESPI_CH0_CTRL); +} + -+static void ast2700_espi_perif_reset(struct aspeed_espi *espi) ++static void ast2700_espi_perif_reset(struct ast2700_espi *espi) +{ -+ struct aspeed_espi_perif *perif; ++ struct ast2700_espi_perif *perif; + struct device *dev; -+ u64 mask; -+ u32 reg; ++ uint64_t mask; ++ uint32_t reg; + + dev = espi->dev; + @@ -80404,11 +72791,11 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + writel(reg, espi->regs + ESPI_MMBI_CTRL); + + mask = ~(perif->mmbi.size - 1); -+ writel(upper_32_bits(mask), espi->regs + ESPI_CH0_MCYC0_MASKH); ++ writel(mask >> 32, espi->regs + ESPI_CH0_MCYC0_MASKH); + writel(mask & 0xffffffff, espi->regs + ESPI_CH0_MCYC0_MASKL); -+ writel(upper_32_bits(perif->mmbi.saddr), espi->regs + ESPI_CH0_MCYC0_SADDRH); ++ writel((perif->mmbi.saddr >> 32), espi->regs + ESPI_CH0_MCYC0_SADDRH); + writel((perif->mmbi.saddr & 0xffffffff), espi->regs + ESPI_CH0_MCYC0_SADDRL); -+ writel(upper_32_bits(perif->mmbi.taddr), espi->regs + ESPI_CH0_MCYC0_TADDRH); ++ writel((perif->mmbi.taddr >> 32), 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); @@ -80427,11 +72814,11 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + + if (perif->mcyc.enable) { + mask = ~(perif->mcyc.size - 1); -+ writel(upper_32_bits(mask), espi->regs + ESPI_CH0_MCYC1_MASKH); ++ writel(mask >> 32, 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 >> 32), 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 >> 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; @@ -80443,11 +72830,11 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + } + + 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 >> 32), 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 >> 32), 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 >> 32), 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) @@ -80468,16 +72855,15 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + writel(reg, espi->regs + ESPI_CH0_CTRL); +} + -+int ast2700_espi_perif_probe(struct aspeed_espi *espi) ++static int ast2700_espi_perif_probe(struct ast2700_espi *espi) +{ -+ struct aspeed_espi_perif_mmbi *mmbi; -+ struct aspeed_espi_perif *perif; ++ 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; -+ u64 temp; + + dev = espi->dev; + @@ -80501,16 +72887,16 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + return -ENODEV; + } + -+ rc = of_property_read_u64(dev->of_node, "perif-mmbi-src-addr", &temp); -+ if (rc || !IS_ALIGNED(temp, PERIF_MMBI_ALIGN)) { ++ 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; + } -+ 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_INST_NUM || ++ 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; @@ -80540,7 +72926,6 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + } + + 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]; @@ -80580,19 +72965,17 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + + 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)) { ++ 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; + } -+ perif->mcyc.saddr = temp; + -+ rc = of_property_read_u64(dev->of_node, "perif-mcyc-size", &temp); -+ if (rc || !IS_ALIGNED(temp, PERIF_MCYC_ALIGN)) { ++ 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; + } -+ perif->mcyc.size = temp; + + np = of_parse_phandle(dev->of_node, "memory-region", 0); + if (np) { @@ -80649,15 +73032,24 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + + 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; +} + -+int ast2700_espi_perif_remove(struct aspeed_espi *espi) ++static int ast2700_espi_perif_remove(struct ast2700_espi *espi) +{ -+ struct aspeed_espi_perif_mmbi *mmbi; -+ struct aspeed_espi_perif *perif; ++ struct ast2700_espi_perif_mmbi *mmbi; ++ struct ast2700_espi_perif *perif; + struct device *dev; -+ u32 reg; ++ uint32_t reg; + int i; + + dev = espi->dev; @@ -80722,13 +73114,13 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as +/* virtual wire channel (CH1) */ +static long ast2700_espi_vw_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ -+ struct aspeed_espi_vw *vw; -+ struct aspeed_espi *espi; -+ u32 gpio0, gpio1; -+ u32 hw_mode; ++ struct ast2700_espi_vw *vw; ++ struct ast2700_espi *espi; ++ uint32_t gpio0, gpio1; ++ uint32_t hw_mode; + -+ vw = container_of(fp->private_data, struct aspeed_espi_vw, mdev); -+ espi = container_of(vw, struct aspeed_espi, vw); ++ 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; @@ -80740,7 +73132,7 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + + switch (cmd) { + case ASPEED_ESPI_VW_GET_GPIO_VAL: -+ if (put_user(gpio0, (u32 __user *)arg)) { ++ if (put_user(gpio0, (uint32_t __user *)arg)) { + dev_err(espi->dev, "failed to get vGPIO value0\n"); + return -EFAULT; + } @@ -80749,7 +73141,7 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + break; + + case ASPEED_ESPI_VW_PUT_GPIO_VAL: -+ if (get_user(gpio0, (u32 __user *)arg)) { ++ if (get_user(gpio0, (uint32_t __user *)arg)) { + dev_err(espi->dev, "failed to put vGPIO value0\n"); + return -EFAULT; + } @@ -80757,9 +73149,9 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + 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)) { ++ if (put_user(gpio1, (uint32_t __user *)arg)) { + dev_err(espi->dev, "failed to get vGPIO value1\n"); + return -EFAULT; + } @@ -80768,7 +73160,7 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + break; + + case ASPEED_ESPI_VW_PUT_GPIO_VAL1: -+ if (get_user(gpio1, (u32 __user *)arg)) { ++ if (get_user(gpio1, (uint32_t __user *)arg)) { + dev_err(espi->dev, "failed to put vGPIO value1\n"); + return -EFAULT; + } @@ -80776,7 +73168,7 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + dev_info(espi->dev, "Put vGPIO value1: 0x%x\n", gpio1); + writel(gpio1, espi->regs + ESPI_CH1_GPIO_VAL1); + break; -+#endif ++ + default: + return -EINVAL; + }; @@ -80789,103 +73181,10 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + .unlocked_ioctl = ast2700_espi_vw_ioctl, +}; + -+static inline struct aspeed_espi_vw *to_ast2700_espi_pltrst(struct file *filp) -+{ -+ 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) ++static void ast2700_espi_vw_isr(struct ast2700_espi *espi) +{ -+ 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; ++ struct ast2700_espi_vw *vw; ++ uint32_t sts; + + vw = &espi->vw; + @@ -80896,29 +73195,12 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + 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 aspeed_espi *espi) ++static void ast2700_espi_vw_reset(struct ast2700_espi *espi) +{ -+ u32 reg; -+ struct aspeed_espi_vw *vw = &espi->vw; ++ uint32_t reg; ++ struct ast2700_espi_vw *vw = &espi->vw; + + writel(0x0, espi->regs + ESPI_CH1_INT_EN); + writel(0xffffffff, espi->regs + ESPI_CH1_INT_STS); @@ -80930,20 +73212,7 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + vw->gpio.val0 = readl(espi->regs + ESPI_CH1_GPIO_VAL0); + vw->gpio.val1 = readl(espi->regs + ESPI_CH1_GPIO_VAL1); + -+ 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); -+ } ++ 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) @@ -80951,36 +73220,17 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + writel(reg, espi->regs + ESPI_CH1_CTRL); +} + -+int ast2700_espi_vw_probe(struct aspeed_espi *espi) ++static int ast2700_espi_vw_probe(struct ast2700_espi *espi) +{ + int rc; + struct device *dev = espi->dev; -+ struct aspeed_espi_vw *vw = &espi->vw; ++ 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); + -+ 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); @@ -80996,9 +73246,9 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + return 0; +} + -+int ast2700_espi_vw_remove(struct aspeed_espi *espi) ++static int ast2700_espi_vw_remove(struct ast2700_espi *espi) +{ -+ struct aspeed_espi_vw *vw; ++ struct ast2700_espi_vw *vw; + + vw = &espi->vw; + @@ -81011,24 +73261,22 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + +/* out-of-band channel (CH2) */ +static long ast2700_espi_oob_dma_get_rx(struct file *fp, -+ struct aspeed_espi_oob *oob, ++ struct ast2700_espi_oob *oob, + struct aspeed_espi_ioc *ioc) +{ + struct ast2700_espi_oob_dma_rx_desc *d; -+ struct ast2700_espi_oob_dma_rx_desc *rx_descs; -+ struct aspeed_espi *espi; ++ struct ast2700_espi *espi; + struct espi_comm_hdr *hdr; -+ u32 wptr, pkt_len; ++ uint32_t wptr, pkt_len; + unsigned long flags; -+ u8 *pkt; ++ uint8_t *pkt; + int rc; + -+ espi = container_of(oob, struct aspeed_espi, oob); ++ 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)); + -+ rx_descs = (struct ast2700_espi_oob_dma_rx_desc *)oob->dma.rxd_virt; -+ d = &rx_descs[wptr]; ++ d = &oob->dma.rxd_virt[wptr]; + + if (!d->dirty) + return -EFAULT; @@ -81062,46 +73310,489 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + wptr = ((wptr + 1) % OOB_DMA_DESC_NUM); + 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 = rx_descs[wptr].dirty; ++ /* set ready flag base on the next RX descriptor */ ++ oob->rx_ready = oob->dma.rxd_virt[wptr].dirty; ++ ++ spin_unlock_irqrestore(&oob->lock, flags); ++ ++ rc = 0; ++ ++free_n_out: ++ vfree(pkt); ++ ++ return rc; ++} ++ ++static long ast2700_espi_oob_get_rx(struct file *fp, ++ struct ast2700_espi_oob *oob, ++ struct aspeed_espi_ioc *ioc) ++{ ++ 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; ++ ++ espi = container_of(oob, struct ast2700_espi, oob); ++ ++ if (fp->f_flags & O_NONBLOCK) { ++ if (!mutex_trylock(&oob->rx_mtx)) ++ return -EAGAIN; ++ ++ if (!oob->rx_ready) { ++ rc = -ENODATA; ++ goto unlock_mtx_n_out; ++ } ++ } else { ++ mutex_lock(&oob->rx_mtx); ++ ++ if (!oob->rx_ready) { ++ rc = wait_event_interruptible(oob->wq, oob->rx_ready); ++ if (rc == -ERESTARTSYS) { ++ rc = -EINTR; ++ goto unlock_mtx_n_out; ++ } ++ } ++ } ++ ++ if (oob->dma.enable) { ++ rc = ast2700_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_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); ++ ++ /* ++ * 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); ++ ++ 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; ++ ++ for (i = sizeof(*hdr); i < pkt_len; ++i) { ++ reg = readl(espi->regs + ESPI_CH2_RX_DATA); ++ pkt[i] = reg & 0xff; ++ } ++ ++ if (copy_to_user((void __user *)ioc->pkt, pkt, pkt_len)) { ++ rc = -EFAULT; ++ goto free_n_out; ++ } ++ ++ spin_lock_irqsave(&oob->lock, flags); ++ ++ writel(ESPI_CH2_RX_CTRL_SERV_PEND, espi->regs + ESPI_CH2_RX_CTRL); ++ oob->rx_ready = 0; ++ ++ spin_unlock_irqrestore(&oob->lock, flags); ++ ++ rc = 0; ++ ++free_n_out: ++ vfree(pkt); ++ ++unlock_mtx_n_out: ++ mutex_unlock(&oob->rx_mtx); ++ ++ return rc; ++} ++ ++static long ast2700_espi_oob_dma_put_tx(struct file *fp, ++ struct ast2700_espi_oob *oob, ++ struct aspeed_espi_ioc *ioc) ++{ ++ 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; ++ ++ espi = container_of(oob, struct ast2700_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_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; ++ } ++ ++ 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_CH2_TX_DESC_WPTR_VALID, espi->regs + ESPI_CH2_TX_DESC_WPTR); ++ ++ rc = 0; ++ ++free_n_out: ++ vfree(pkt); ++ ++ return rc; ++} ++ ++static long ast2700_espi_oob_put_tx(struct file *fp, ++ struct ast2700_espi_oob *oob, ++ struct aspeed_espi_ioc *ioc) ++{ ++ 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); ++ ++ 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; ++ } ++ ++ reg = readl(espi->regs + ESPI_CH2_TX_CTRL); ++ if (reg & ESPI_CH2_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_CH2_TX_DATA); ++ ++ cyc = hdr->cyc; ++ tag = hdr->tag; ++ len = (hdr->len_h << 8) | (hdr->len_l & 0xff); ++ ++ 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 long ast2700_espi_oob_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) ++{ ++ struct ast2700_espi_oob *oob; ++ struct aspeed_espi_ioc ioc; ++ ++ oob = container_of(fp->private_data, struct ast2700_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 const struct file_operations ast2700_espi_oob_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = ast2700_espi_oob_ioctl, ++}; ++ ++static void ast2700_espi_oob_isr(struct ast2700_espi *espi) ++{ ++ struct ast2700_espi_oob *oob; ++ unsigned long flags; ++ uint32_t sts; ++ ++ oob = &espi->oob; ++ ++ 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); ++ } ++} ++ ++static void ast2700_espi_oob_reset(struct ast2700_espi *espi) ++{ ++ 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); ++ ++ 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; ++ ++ 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; ++ ++ 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; ++ } ++ ++ 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); ++ ++ 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); ++ ++ 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); ++ } ++ ++ 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) ++{ ++ struct ast2700_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%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; ++ } ++ ++ ast2700_espi_oob_reset(espi); ++ ++ return 0; ++} ++ ++static int ast2700_espi_oob_remove(struct ast2700_espi *espi) ++{ ++ struct ast2700_espi_oob *oob; ++ struct device *dev; ++ uint32_t reg; ++ ++ dev = espi->dev; ++ ++ oob = &espi->oob; ++ ++ 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); + -+ spin_unlock_irqrestore(&oob->lock, flags); ++ 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); ++ } + -+ rc = 0; ++ mutex_destroy(&oob->tx_mtx); ++ mutex_destroy(&oob->rx_mtx); + -+free_n_out: -+ vfree(pkt); ++ misc_deregister(&oob->mdev); + -+ return rc; ++ return 0; +} + -+static long ast2700_espi_oob_get_rx(struct file *fp, -+ struct aspeed_espi_oob *oob, -+ struct aspeed_espi_ioc *ioc) ++/* flash channel (CH3) */ ++static long ast2700_espi_flash_get_rx(struct file *fp, ++ struct ast2700_espi_flash *flash, ++ struct aspeed_espi_ioc *ioc) +{ -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; ++ uint32_t reg, cyc, tag, len; ++ struct ast2700_espi *espi; + struct espi_comm_hdr *hdr; + unsigned long flags; -+ u32 pkt_len; -+ u8 *pkt; ++ uint32_t pkt_len; ++ uint8_t *pkt; + int i, rc; + -+ espi = container_of(oob, struct aspeed_espi, oob); ++ rc = 0; ++ ++ espi = container_of(flash, struct ast2700_espi, flash); + + if (fp->f_flags & O_NONBLOCK) { -+ if (!mutex_trylock(&oob->rx_mtx)) ++ if (!mutex_trylock(&flash->rx_mtx)) + return -EAGAIN; + -+ if (!oob->rx_ready) { ++ if (!flash->rx_ready) { + rc = -ENODATA; + goto unlock_mtx_n_out; + } + } else { -+ mutex_lock(&oob->rx_mtx); ++ mutex_lock(&flash->rx_mtx); + -+ if (!oob->rx_ready) { -+ rc = wait_event_interruptible(oob->wq, oob->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; @@ -81109,26 +73800,44 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + } + } + -+ if (oob->dma.enable) { -+ rc = ast2700_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_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); ++ 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. + */ -+ pkt_len = ((len) ? len : ESPI_MAX_PLD_LEN) + sizeof(struct espi_comm_hdr); ++ 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; @@ -81147,9 +73856,11 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + hdr->len_h = len >> 8; + hdr->len_l = len & 0xff; + -+ for (i = sizeof(*hdr); i < pkt_len; ++i) { -+ reg = readl(espi->regs + ESPI_CH2_RX_DATA); -+ pkt[i] = reg & 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)) { @@ -81157,12 +73868,12 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + goto free_n_out; + } + -+ spin_lock_irqsave(&oob->lock, flags); ++ spin_lock_irqsave(&flash->lock, flags); + -+ writel(ESPI_CH2_RX_CTRL_SERV_PEND, espi->regs + ESPI_CH2_RX_CTRL); -+ oob->rx_ready = 0; ++ writel(ESPI_CH3_RX_CTRL_SERV_PEND, espi->regs + ESPI_CH3_RX_CTRL); ++ flash->rx_ready = 0; + -+ spin_unlock_irqrestore(&oob->lock, flags); ++ spin_unlock_irqrestore(&flash->lock, flags); + + rc = 0; + @@ -81170,100 +73881,32 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + vfree(pkt); + +unlock_mtx_n_out: -+ mutex_unlock(&oob->rx_mtx); -+ -+ return rc; -+} -+ -+static long ast2700_espi_oob_dma_put_tx(struct file *fp, -+ struct aspeed_espi_oob *oob, -+ struct aspeed_espi_ioc *ioc) -+{ -+ 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; -+ -+ espi = container_of(oob, struct aspeed_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_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; -+ } -+ -+ 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); ++ mutex_unlock(&flash->rx_mtx); + + return rc; +} + -+static long ast2700_espi_oob_put_tx(struct file *fp, -+ struct aspeed_espi_oob *oob, -+ struct aspeed_espi_ioc *ioc) ++static long ast2700_espi_flash_put_tx(struct file *fp, ++ struct ast2700_espi_flash *flash, ++ struct aspeed_espi_ioc *ioc) +{ -+ u32 reg, cyc, tag, len; -+ struct aspeed_espi *espi; ++ uint32_t reg, cyc, tag, len; ++ struct ast2700_espi *espi; + struct espi_comm_hdr *hdr; -+ u8 *pkt; ++ uint8_t *pkt; + int i, rc; + -+ espi = container_of(oob, struct aspeed_espi, oob); ++ espi = container_of(flash, struct ast2700_espi, flash); + -+ if (!mutex_trylock(&oob->tx_mtx)) ++ if (!mutex_trylock(&flash->tx_mtx)) + return -EAGAIN; + -+ if (oob->dma.enable) { -+ rc = ast2700_espi_oob_dma_put_tx(fp, oob, ioc); -+ goto unlock_mtx_n_out; -+ } -+ -+ reg = readl(espi->regs + ESPI_CH2_TX_CTRL); -+ if (reg & ESPI_CH2_TX_CTRL_TRIG_PEND) { ++ reg = readl(espi->regs + ESPI_CH3_TX_CTRL); ++ if (reg & ESPI_CH3_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; @@ -81281,18 +73924,23 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + * 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); ++ 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); ++ } + + cyc = hdr->cyc; + tag = hdr->tag; + len = (hdr->len_h << 8) | (hdr->len_l & 0xff); + -+ 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); ++ 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); + + rc = 0; + @@ -81300,17 +73948,17 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + vfree(pkt); + +unlock_mtx_n_out: -+ mutex_unlock(&oob->tx_mtx); ++ mutex_unlock(&flash->tx_mtx); + + return rc; +} + -+static long ast2700_espi_oob_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) ++static long ast2700_espi_flash_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ -+ struct aspeed_espi_oob *oob; ++ struct ast2700_espi_flash *flash; + struct aspeed_espi_ioc ioc; + -+ oob = container_of(fp->private_data, struct aspeed_espi_oob, mdev); ++ flash = container_of(fp->private_data, struct ast2700_espi_flash, mdev); + + if (copy_from_user(&ioc, (void __user *)arg, sizeof(ioc))) + return -EFAULT; @@ -81319,1000 +73967,1265 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-espi.c b/drivers/soc/aspeed/espi/as + 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); ++ 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 const struct file_operations ast2700_espi_oob_fops = { ++static const struct file_operations ast2700_espi_flash_fops = { + .owner = THIS_MODULE, -+ .unlocked_ioctl = ast2700_espi_oob_ioctl, ++ .unlocked_ioctl = ast2700_espi_flash_ioctl, +}; + -+static void ast2700_espi_oob_isr(struct aspeed_espi *espi) ++static void ast2700_espi_flash_isr(struct ast2700_espi *espi) +{ -+ struct aspeed_espi_oob *oob; ++ struct ast2700_espi_flash *flash; + unsigned long flags; -+ u32 sts; ++ uint32_t sts; + -+ oob = &espi->oob; ++ flash = &espi->flash; + -+ sts = readl(espi->regs + ESPI_CH2_INT_STS); ++ sts = readl(espi->regs + ESPI_CH3_INT_STS); + -+ if (sts & ESPI_CH2_INT_STS_RX_CMPLT) { -+ writel(ESPI_CH2_INT_STS_RX_CMPLT, espi->regs + ESPI_CH2_INT_STS); ++ if (sts & ESPI_CH3_INT_STS_RX_CMPLT) { ++ writel(ESPI_CH3_INT_STS_RX_CMPLT, espi->regs + ESPI_CH3_INT_STS); + -+ spin_lock_irqsave(&oob->lock, flags); -+ oob->rx_ready = true; -+ spin_unlock_irqrestore(&oob->lock, flags); ++ spin_lock_irqsave(&flash->lock, flags); ++ flash->rx_ready = true; ++ spin_unlock_irqrestore(&flash->lock, flags); + -+ wake_up_interruptible(&oob->wq); ++ wake_up_interruptible(&flash->wq); + } +} + -+static void ast2700_espi_oob_reset(struct aspeed_espi *espi) ++static void ast2700_espi_flash_reset(struct ast2700_espi *espi) +{ -+ 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; -+ -+ oob = &espi->oob; ++ uint32_t reg; ++ uint64_t mask; ++ struct ast2700_espi_flash *flash = &espi->flash; + -+ writel(0x0, espi->regs + ESPI_CH2_INT_EN); -+ writel(0xffffffff, espi->regs + ESPI_CH2_INT_STS); ++ writel(0x0, espi->regs + ESPI_CH3_INT_EN); ++ writel(0xffffffff, espi->regs + ESPI_CH3_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); ++ 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); + -+ reg |= (ESPI_CH2_CTRL_TX_RST | ESPI_CH2_CTRL_RX_RST); -+ writel(reg, espi->regs + ESPI_CH2_CTRL); ++ reg |= (ESPI_CH3_CTRL_TX_RST | ESPI_CH3_CTRL_RX_RST); ++ writel(reg, espi->regs + ESPI_CH3_CTRL); + -+ if (oob->dma.enable) { -+ tx_addr = oob->dma.tx_addr; -+ rx_addr = oob->dma.rx_addr; ++ 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); ++ } + -+ 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; ++ 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); + -+ 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; ++ 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); + -+ 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; ++ 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); ++} ++ ++static int ast2700_espi_flash_probe(struct ast2700_espi *espi) ++{ ++ struct ast2700_espi_flash *flash; ++ struct device_node *np; ++ struct resource res; ++ struct device *dev; ++ void *virt; ++ int rc; ++ ++ dev = espi->dev; ++ ++ flash = &espi->flash; ++ ++ init_waitqueue_head(&flash->wq); ++ ++ spin_lock_init(&flash->lock); ++ ++ mutex_init(&flash->tx_mtx); ++ mutex_init(&flash->rx_mtx); ++ ++ flash->edaf.mode = EDAF_MODE_HW; ++ ++ 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; + } + -+ 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); ++ of_node_put(np); + -+ 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); ++ 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); + -+ 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); ++ virt = devm_ioremap_resource(dev, &res); ++ if (!virt) { ++ dev_err(dev, "cannot map eDAF memory region\n"); ++ return -ENOMEM; ++ } ++ } + -+ /* 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); ++ 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; ++ } ++ ++ 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; ++ } ++ } ++ ++ 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; ++ } ++ ++ ast2700_espi_flash_reset(espi); ++ ++ return 0; ++} ++ ++static int ast2700_espi_flash_remove(struct ast2700_espi *espi) ++{ ++ struct ast2700_espi_flash *flash; ++ struct device *dev; ++ uint32_t reg; ++ ++ dev = espi->dev; ++ ++ flash = &espi->flash; ++ ++ writel(0x0, espi->regs + ESPI_CH3_INT_EN); ++ ++ 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 (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 */ ++static irqreturn_t ast2700_espi_isr(int irq, void *arg) ++{ ++ uint32_t sts; ++ struct ast2700_espi *espi = (struct ast2700_espi *)arg; ++ ++ sts = readl(espi->regs + ESPI_INT_STS); ++ if (!sts) ++ return IRQ_NONE; ++ ++ if (sts & ESPI_INT_STS_CH0) ++ ast2700_espi_perif_isr(espi); ++ ++ if (sts & ESPI_INT_STS_CH1) ++ ast2700_espi_vw_isr(espi); ++ ++ if (sts & ESPI_INT_STS_CH2) ++ ast2700_espi_oob_isr(espi); ++ ++ if (sts & ESPI_INT_STS_CH3) ++ ast2700_espi_flash_isr(espi); ++ ++ 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 IRQ_HANDLED; ++} ++ ++static int ast2700_espi_probe(struct platform_device *pdev) ++{ ++ struct ast2700_espi *espi; ++ struct resource *res; ++ struct device *dev; ++ struct regmap *scu1; ++ 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; ++ } ++ ++ 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); ++ ++ 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; ++ } ++ ++ 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; ++ } ++ ++ 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; + } + -+ writel(ESPI_CH2_INT_EN_RX_CMPLT, espi->regs + ESPI_CH2_INT_EN); ++ 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; + -+ reg = readl(espi->regs + ESPI_CH2_CTRL) | ESPI_CH2_CTRL_SW_RDY; -+ writel(reg, espi->regs + ESPI_CH2_CTRL); ++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; +} + -+int ast2700_espi_oob_probe(struct aspeed_espi *espi) ++static void ast2700_espi_remove(struct platform_device *pdev) +{ -+ struct aspeed_espi_oob *oob; ++ struct ast2700_espi *espi; + struct device *dev; ++ uint32_t reg; + int rc; + -+ dev = espi->dev; ++ dev = &pdev->dev; + -+ oob = &espi->oob; ++ espi = platform_get_drvdata(pdev); + -+ init_waitqueue_head(&oob->wq); ++ reg = readl(espi->regs + ESPI_INT_EN); ++ reg &= ~ESPI_INT_EN_RST_DEASSERT; ++ writel(reg, espi->regs + ESPI_INT_EN); + -+ spin_lock_init(&oob->lock); ++ rc = ast2700_espi_perif_remove(espi); ++ if (rc) ++ dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); + -+ mutex_init(&oob->tx_mtx); -+ mutex_init(&oob->rx_mtx); ++ rc = ast2700_espi_vw_remove(espi); ++ if (rc) ++ dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); + -+ 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; -+ } ++ rc = ast2700_espi_oob_remove(espi); ++ if (rc) ++ dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); + -+ 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; -+ } ++ rc = ast2700_espi_flash_remove(espi); ++ if (rc) ++ dev_warn(dev, "cannot remove peripheral channel, rc=%d\n", rc); ++} + -+ 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; -+ } -+ } ++static const struct of_device_id ast2700_espi_of_matches[] = { ++ { .compatible = "aspeed,ast2700-espi" }, ++ { }, ++}; + -+ 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; -+ } ++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, ++}; + -+ ast2700_espi_oob_reset(espi); ++module_platform_driver(ast2700_espi_driver); + -+ return 0; -+} ++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_ + -+int ast2700_espi_oob_remove(struct aspeed_espi *espi) -+{ -+ struct aspeed_espi_oob *oob; -+ struct device *dev; -+ u32 reg; ++#include ++#include "aspeed-espi-comm.h" + -+ dev = espi->dev; ++/* SCU regiseters */ ++#define SCU1_DDR 0x0c8 ++#define SCU1_DDR_DIS_ESPI0_AHB BIT(0) ++#define SCU1_DDR_DIS_ESPI1_AHB BIT(1) + -+ oob = &espi->oob; ++/* 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 + -+ writel(0x0, espi->regs + ESPI_CH2_INT_EN); ++/* 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 + -+ 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); ++/* 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 + -+ 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); -+ } ++/* 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 + -+ mutex_destroy(&oob->tx_mtx); -+ mutex_destroy(&oob->rx_mtx); ++/* 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 + -+ misc_deregister(&oob->mdev); ++/* 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 + -+ return 0; -+} ++/* 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)) + -+/* flash channel (CH3) */ -+static long ast2700_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; ++enum ast2700_edaf_mode { ++ EDAF_MODE_MIX, ++ EDAF_MODE_SW, ++ EDAF_MODE_HW, ++ EDAF_MODES, ++}; + -+ rc = 0; ++#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. ++ */ + -+ espi = container_of(flash, struct aspeed_espi, flash); ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ if (fp->f_flags & O_NONBLOCK) { -+ if (!mutex_trylock(&flash->rx_mtx)) -+ return -EAGAIN; ++static DEFINE_SPINLOCK(otp_state_lock); + -+ if (!flash->rx_ready) { -+ rc = -ENODATA; -+ goto unlock_mtx_n_out; -+ } -+ } else { -+ mutex_lock(&flash->rx_mtx); ++/*********************** ++ * * ++ * OTP regs definition * ++ * * ++ ***********************/ ++#define OTP_REG_SIZE 0x200 + -+ if (!flash->rx_ready) { -+ rc = wait_event_interruptible(flash->wq, flash->rx_ready); -+ if (rc == -ERESTARTSYS) { -+ rc = -EINTR; -+ goto unlock_mtx_n_out; -+ } -+ } -+ } ++#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 + -+ /* -+ * 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); ++#define OTP_CMD_OFFSET 0x20 ++#define OTP_MASTER OTP_M0 + -+ /* -+ * 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; -+ } ++#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) + -+ if (ioc->pkt_len < pkt_len) { -+ rc = -EINVAL; -+ goto unlock_mtx_n_out; -+ } ++#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 + -+ pkt = vmalloc(pkt_len); -+ if (!pkt) { -+ rc = -ENOMEM; -+ goto unlock_mtx_n_out; -+ } ++#define OTP_PMC 0x400 ++#define OTP_DAP 0x500 + -+ hdr = (struct espi_comm_hdr *)pkt; -+ hdr->cyc = cyc; -+ hdr->tag = tag; -+ hdr->len_h = len >> 8; -+ hdr->len_l = len & 0xff; ++/* OTP status: [0] */ ++#define OTP_STS_IDLE 0x0 ++#define OTP_STS_BUSY 0x1 + -+ 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; -+ } ++/* 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 + -+ if (copy_to_user((void __user *)ioc->pkt, pkt, pkt_len)) { -+ rc = -EFAULT; -+ goto free_n_out; -+ } ++/* OTP ECC EN */ ++#define ECC_ENABLE 0x1 ++#define ECC_DISABLE 0x0 ++#define ECCBRP_EN BIT(0) + -+ spin_lock_irqsave(&flash->lock, flags); ++#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 + -+ writel(ESPI_CH3_RX_CTRL_SERV_PEND, espi->regs + ESPI_CH3_RX_CTRL); -+ flash->rx_ready = 0; ++#define OTP_MEMORY_SIZE (HW_PUF_REGION_END_ADDR * 2) + -+ spin_unlock_irqrestore(&flash->lock, flags); ++#define OTP_TIMEOUT_US 10000 + -+ rc = 0; ++/* OTPSTRAP */ ++#define OTPSTRAP0_ADDR STRAP_REGION_START_ADDR ++#define OTPSTRAP14_ADDR (OTPSTRAP0_ADDR + 0xe) + -+free_n_out: -+ vfree(pkt); ++#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 + -+unlock_mtx_n_out: -+ mutex_unlock(&flash->rx_mtx); ++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 long ast2700_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; ++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; ++}; + -+ espi = container_of(flash, struct aspeed_espi, flash); ++enum otp_ioctl_cmds { ++ GET_ECC_STATUS = 1, ++ SET_ECC_ENABLE, ++}; + -+ if (!mutex_trylock(&flash->tx_mtx)) -+ return -EAGAIN; ++enum otp_ecc_codes { ++ OTP_ECC_MISMATCH = -1, ++ OTP_ECC_DISABLE = 0, ++ OTP_ECC_ENABLE = 1, ++}; + -+ reg = readl(espi->regs + ESPI_CH3_TX_CTRL); -+ if (reg & ESPI_CH3_TX_CTRL_TRIG_PEND) { -+ rc = -EBUSY; -+ goto unlock_mtx_n_out; -+ } ++static void otp_unlock(struct device *dev) ++{ ++ struct aspeed_otp *ctx = dev_get_drvdata(dev); + -+ pkt = vmalloc(ioc->pkt_len); -+ if (!pkt) { -+ rc = -ENOMEM; -+ goto unlock_mtx_n_out; -+ } ++ writel(OTP_PASSWD, ctx->base + OTP_KEY); ++} + -+ hdr = (struct espi_comm_hdr *)pkt; ++static void otp_lock(struct device *dev) ++{ ++ struct aspeed_otp *ctx = dev_get_drvdata(dev); + -+ if (copy_from_user(pkt, (void __user *)ioc->pkt, ioc->pkt_len)) { -+ rc = -EFAULT; -+ goto free_n_out; -+ } ++ writel(0x1, ctx->base + OTP_KEY); ++} + -+ /* -+ * 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); -+ } ++static int wait_complete(struct device *dev) ++{ ++ struct aspeed_otp *ctx = dev_get_drvdata(dev); ++ int ret; ++ u32 val; + -+ cyc = hdr->cyc; -+ tag = hdr->tag; -+ len = (hdr->len_h << 8) | (hdr->len_l & 0xff); ++ 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); + -+ 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); ++ return ret; ++} + -+ rc = 0; ++static int otp_read_data(struct aspeed_otp *ctx, u32 offset, u16 *data) ++{ ++ struct device *dev = ctx->dev; ++ int ret; + -+free_n_out: -+ vfree(pkt); ++ 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; + -+unlock_mtx_n_out: -+ mutex_unlock(&flash->tx_mtx); ++ data[0] = readl(ctx->base + OTP_RDATA); + -+ return rc; ++ return 0; +} + -+static long ast2700_espi_flash_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) ++static int otp_prog_data(struct aspeed_otp *ctx, u32 offset, u16 data) +{ -+ struct aspeed_espi_flash *flash; -+ struct aspeed_espi_ioc ioc; -+ -+ 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; ++ struct device *dev = ctx->dev; ++ int ret; + -+ 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); -+ }; ++ 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 -EINVAL; ++ return 0; +} + -+static const struct file_operations ast2700_espi_flash_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = ast2700_espi_flash_ioctl, -+}; -+ -+static void ast2700_espi_flash_isr(struct aspeed_espi *espi) ++static int otp_prog_multi_data(struct aspeed_otp *ctx, u32 offset, u32 *data, int count) +{ -+ struct aspeed_espi_flash *flash; -+ unsigned long flags; -+ u32 sts; ++ struct device *dev = ctx->dev; ++ int ret; + -+ flash = &espi->flash; ++ 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); + -+ sts = readl(espi->regs + ESPI_CH3_INT_STS); ++ writel(OTP_CMD_PROG_MULTI, ctx->base + OTP_CMD); ++ ret = wait_complete(dev); ++ if (ret) ++ return OTP_PROG_FAIL; + -+ if (sts & ESPI_CH3_INT_STS_RX_CMPLT) { -+ writel(ESPI_CH3_INT_STS_RX_CMPLT, espi->regs + ESPI_CH3_INT_STS); ++ return 0; ++} + -+ spin_lock_irqsave(&flash->lock, flags); -+ flash->rx_ready = true; -+ spin_unlock_irqrestore(&flash->lock, flags); ++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; + -+ wake_up_interruptible(&flash->wq); ++ 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; ++ } + } ++ ++ otp_lock(dev); ++ return ret; +} + -+static void ast2700_espi_flash_reset(struct aspeed_espi *espi) ++static int aspeed_otp_write(struct aspeed_otp *ctx, int offset, ++ const void *buf, int size) +{ -+ u32 reg; -+ u64 mask; -+ struct aspeed_espi_flash *flash = &espi->flash; ++ struct device *dev = ctx->dev; ++ u32 *data32 = (u32 *)buf; ++ u16 *data = (u16 *)buf; ++ int ret; + -+ writel(0x0, espi->regs + ESPI_CH3_INT_EN); -+ writel(0xffffffff, espi->regs + ESPI_CH3_INT_STS); ++ otp_unlock(dev); + -+ 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); ++ if (size == 1) ++ ret = otp_prog_data(ctx, offset, data[0]); ++ else ++ ret = otp_prog_multi_data(ctx, offset, data32, size / 2); + -+ udelay(1); ++ if (ret) ++ dev_warn(ctx->dev, "prog failed\n"); + -+ reg |= (ESPI_CH3_CTRL_TX_RST | ESPI_CH3_CTRL_RX_RST); -+ writel(reg, espi->regs + ESPI_CH3_CTRL); ++ otp_lock(dev); ++ return ret; ++} + -+ 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); -+ } ++static int aspeed_otp_ecc_en(struct aspeed_otp *ctx) ++{ ++ struct device *dev = ctx->dev; ++ int ret = 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); ++ /* Check ecc is already enabled */ ++ if (ctx->gbl_ecc_en == 1) ++ return 0; + -+ 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); ++ otp_unlock(dev); + -+ 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); ++ /* enable cfg ecc */ ++ ret = otp_prog_data(ctx, OTPSTRAP14_ADDR, 0x1); ++ if (ret) { ++ dev_warn(dev, "%s: prog failed\n", __func__); ++ goto end; + } + -+ writel(ESPI_CH3_INT_EN_RX_CMPLT, espi->regs + ESPI_CH3_INT_EN); ++ ctx->gbl_ecc_en = 1; ++end: ++ otp_lock(dev); + -+ reg = readl(espi->regs + ESPI_CH3_CTRL) | ESPI_CH3_CTRL_SW_RDY; -+ writel(reg, espi->regs + ESPI_CH3_CTRL); ++ return ret; +} + -+int ast2700_espi_flash_probe(struct aspeed_espi *espi) ++static long aspeed_otp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ -+ struct aspeed_espi_flash *flash; -+ struct device_node *np; -+ struct resource res; -+ struct device *dev; -+ void *virt; -+ int rc; -+ -+ dev = espi->dev; -+ -+ flash = &espi->flash; -+ -+ init_waitqueue_head(&flash->wq); -+ -+ spin_lock_init(&flash->lock); ++ 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; + -+ mutex_init(&flash->tx_mtx); -+ mutex_init(&flash->rx_mtx); ++ switch (cmd) { ++ case ASPEED_OTP_READ_DATA: ++ if (copy_from_user(&rdata, argp, sizeof(struct otp_read))) ++ return -EFAULT; + -+ flash->edaf.mode = EDAF_MODE_HW; ++ ret = aspeed_otp_read(ctx, rdata.offset, ctx->data, rdata.len); ++ if (ret) ++ return -EFAULT; + -+ 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; -+ } ++ if (copy_to_user(rdata.data, ctx->data, rdata.len * 2)) ++ return -EFAULT; + -+ of_node_put(np); ++ break; + -+ flash->edaf.taddr = res.start; -+ flash->edaf.size = resource_size(&res); ++ case ASPEED_OTP_PROG_DATA: ++ if (copy_from_user(&pdata, argp, sizeof(struct otp_prog))) ++ return -EFAULT; + -+ virt = devm_ioremap_resource(dev, &res); -+ if (!virt) { -+ dev_err(dev, "cannot map eDAF memory region\n"); -+ return -ENOMEM; -+ } -+ } ++ ret = aspeed_otp_write(ctx, pdata.w_offset, pdata.data, pdata.len); ++ break; + -+ 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; -+ } ++ case ASPEED_OTP_GET_ECC: ++ if (copy_to_user(argp, &ctx->gbl_ecc_en, sizeof(ctx->gbl_ecc_en))) ++ return -EFAULT; ++ break; + -+ 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; -+ } -+ } ++ case ASPEED_OTP_SET_ECC: ++ ret = aspeed_otp_ecc_en(ctx); ++ break; + -+ 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; ++ 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; + } + -+ ast2700_espi_flash_reset(espi); -+ -+ return 0; ++ return ret; +} + -+int ast2700_espi_flash_remove(struct aspeed_espi *espi) ++static int aspeed_otp_ecc_init(struct device *dev) +{ -+ struct aspeed_espi_flash *flash; -+ struct device *dev; -+ u32 reg; -+ -+ dev = espi->dev; -+ -+ flash = &espi->flash; -+ -+ writel(0x0, espi->regs + ESPI_CH3_INT_EN); ++ struct aspeed_otp *ctx = dev_get_drvdata(dev); ++ int ret; ++ u32 val; + -+ 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); ++ otp_unlock(dev); + -+ 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); -+ } ++ /* 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; + -+ mutex_destroy(&flash->tx_mtx); -+ mutex_destroy(&flash->rx_mtx); ++ val = readl(ctx->base + OTP_RDATA); ++ if (val & 0x1) ++ ctx->gbl_ecc_en = 0x1; ++ else ++ ctx->gbl_ecc_en = 0x0; + -+ misc_deregister(&flash->mdev); ++ otp_lock(dev); + + return 0; +} + -+/* global control */ -+irqreturn_t ast2700_espi_isr(int irq, void *arg) ++static int aspeed_otp_open(struct inode *inode, struct file *file) +{ -+ u32 sts; -+ struct aspeed_espi *espi = (struct aspeed_espi *)arg; -+ -+ sts = readl(espi->regs + ESPI_INT_STS); -+ if (!sts) -+ return IRQ_NONE; -+ -+ if (sts & ESPI_INT_STS_CH0) -+ ast2700_espi_perif_isr(espi); -+ -+ if (sts & ESPI_INT_STS_CH1) -+ ast2700_espi_vw_isr(espi); -+ -+ if (sts & ESPI_INT_STS_CH2) -+ ast2700_espi_oob_isr(espi); -+ -+ if (sts & ESPI_INT_STS_CH3) -+ ast2700_espi_flash_isr(espi); -+ -+ 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); ++ struct miscdevice *c = file->private_data; ++ struct aspeed_otp *ctx = container_of(c, struct aspeed_otp, miscdev); ++ ++ spin_lock(&otp_state_lock); ++ ++ if (ctx->is_open) { ++ spin_unlock(&otp_state_lock); ++ return -EBUSY; + } + -+ return IRQ_HANDLED; ++ ctx->is_open = true; ++ ++ spin_unlock(&otp_state_lock); ++ ++ return 0; +} + -+void ast2700_espi_pre_init(struct aspeed_espi *espi) ++static int aspeed_otp_release(struct inode *inode, struct file *file) +{ -+ struct device *dev; -+ struct regmap *scu1; -+ u32 reg; -+ int rc; ++ struct miscdevice *c = file->private_data; ++ struct aspeed_otp *ctx = container_of(c, struct aspeed_otp, miscdev); + -+ dev = espi->dev; ++ spin_lock(&otp_state_lock); + -+ scu1 = syscon_regmap_lookup_by_phandle(dev->of_node, "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; -+ } ++ ctx->is_open = false; + -+ 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; -+ } ++ spin_unlock(&otp_state_lock); + -+ reg = readl(espi->regs + ESPI_INT_EN); -+ reg &= ~ESPI_INT_EN_RST_DEASSERT; -+ writel(reg, espi->regs + ESPI_INT_EN); ++ return 0; +} + -+void ast2700_espi_post_init(struct aspeed_espi *espi) -+{ -+ u32 reg; ++static const struct file_operations otp_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = aspeed_otp_ioctl, ++ .open = aspeed_otp_open, ++ .release = aspeed_otp_release, ++}; + -+ reg = readl(espi->regs + ESPI_INT_EN); -+ reg |= ESPI_INT_EN_RST_DEASSERT; -+ writel(reg, espi->regs + ESPI_INT_EN); -+} ++static const struct of_device_id aspeed_otp_of_matches[] = { ++ { .compatible = "aspeed,ast2700-otp" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, aspeed_otp_of_matches); + -+void ast2700_espi_deinit(struct aspeed_espi *espi) ++static int aspeed_otp_probe(struct platform_device *pdev) +{ -+ struct device *dev; -+ u32 reg; ++ struct device *dev = &pdev->dev; ++ struct regmap *scu0, *scu1; ++ struct aspeed_otp *priv; ++ struct resource *res; ++ int rc; + -+ dev = espi->dev; ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; + -+ 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-04-08 18:03:48.313705265 +0000 -@@ -0,0 +1,296 @@ -+/* 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_ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "cannot get IORESOURCE_MEM\n"); ++ return -ENOENT; ++ } + -+#include -+#include "aspeed-espi.h" ++ priv->base = devm_ioremap_resource(&pdev->dev, res); ++ if (!priv->base) ++ return -EIO; + -+/* SCU regiseters */ -+#define SCU1_DDR 0x0c8 -+#define SCU1_DDR_DIS_ESPI0_AHB BIT(0) -+#define SCU1_DDR_DIS_ESPI1_AHB BIT(1) ++ 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); ++ } + -+/* 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 ++ regmap_read(scu0, 0x0, &priv->chip_revid0); ++ regmap_read(scu1, 0x0, &priv->chip_revid1); + -+/* 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 ++ priv->dev = dev; ++ dev_set_drvdata(dev, priv); + -+/* 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_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 -+#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 ++ /* OTP ECC init */ ++ rc = aspeed_otp_ecc_init(dev); ++ if (rc) ++ return -EIO; + -+/* 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 ++ priv->data = kmalloc(OTP_MEMORY_SIZE, GFP_KERNEL); ++ if (!priv->data) ++ return -ENOMEM; + -+/* 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 ++ /* Set up the miscdevice */ ++ priv->miscdev.minor = MISC_DYNAMIC_MINOR; ++ priv->miscdev.name = "aspeed-otp"; ++ priv->miscdev.fops = &otp_fops; + -+/* 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 ++ /* Register the device */ ++ rc = misc_register(&priv->miscdev); ++ if (rc) { ++ dev_err(dev, "Unable to register device\n"); ++ return rc; ++ } + -+/* 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)) ++ dev_info(dev, "Aspeed OTP driver successfully registered\n"); + -+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); ++ return 0; ++} + -+#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-04-08 18:03:48.313705265 +0000 ++static void aspeed_otp_remove(struct platform_device *pdev) ++{ ++ struct aspeed_otp *ctx = dev_get_drvdata(&pdev->dev); ++ ++ kfree(ctx->data); ++ misc_deregister(&ctx->miscdev); ++} ++ ++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, ++ }, ++}; ++ ++module_platform_driver(aspeed_otp_driver); ++ ++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 +/* @@ -82509,7 +75422,7 @@ diff --git a/drivers/soc/aspeed/espi/ast2700-rtc-over-espi.c b/drivers/soc/aspee +MODULE_DESCRIPTION("RTC to eSPI RAM sync driver"); 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 2026-04-08 18:03:48.313705265 +0000 ++++ b/drivers/soc/aspeed/rvas/Kconfig 2025-12-23 10:16:21.127032619 +0000 @@ -0,0 +1,9 @@ +menu "ASPEED RVAS drivers" + @@ -82522,14 +75435,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 2026-04-08 18:03:48.313705265 +0000 ++++ b/drivers/soc/aspeed/rvas/Makefile 2025-12-23 10:16:21.127032619 +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 2026-04-08 18:03:48.313705265 +0000 ++++ b/drivers/soc/aspeed/rvas/hardware_engines.c 2025-12-23 10:16:21.127032619 +0000 @@ -0,0 +1,2201 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* @@ -84734,7 +77647,7 @@ 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 2026-04-08 18:03:48.314705247 +0000 ++++ b/drivers/soc/aspeed/rvas/hardware_engines.h 2025-12-23 10:16:21.127032619 +0000 @@ -0,0 +1,550 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* @@ -85288,7 +78201,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 2026-04-08 18:03:48.314705247 +0000 ++++ b/drivers/soc/aspeed/rvas/video.h 2025-12-23 10:16:21.127032619 +0000 @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/****************************************************************************** @@ -85333,7 +78246,7 @@ 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 2026-04-08 18:03:48.314705247 +0000 ++++ b/drivers/soc/aspeed/rvas/video_debug.h 2025-12-23 10:16:21.127032619 +0000 @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* @@ -85372,7 +78285,7 @@ diff --git a/drivers/soc/aspeed/rvas/video_debug.h b/drivers/soc/aspeed/rvas/vid +#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 2026-04-08 18:03:48.314705247 +0000 ++++ b/drivers/soc/aspeed/rvas/video_engine.c 2025-12-23 10:16:21.127032619 +0000 @@ -0,0 +1,1338 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* @@ -86714,7 +79627,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 2026-04-08 18:03:48.314705247 +0000 ++++ b/drivers/soc/aspeed/rvas/video_engine.h 2025-12-23 10:16:21.127032619 +0000 @@ -0,0 +1,270 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* @@ -86988,7 +79901,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 2026-04-08 18:03:48.314705247 +0000 ++++ b/drivers/soc/aspeed/rvas/video_ioctl.h 2025-12-23 10:16:21.128032602 +0000 @@ -0,0 +1,275 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* @@ -87267,8 +80180,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 2026-04-08 18:03:48.313705265 +0000 -@@ -0,0 +1,1854 @@ ++++ b/drivers/soc/aspeed/rvas/video_main.c 2025-12-23 10:16:21.128032602 +0000 +@@ -0,0 +1,1848 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * File Name : video_main.c @@ -88421,16 +81334,10 @@ diff --git a/drivers/soc/aspeed/rvas/video_main.c b/drivers/soc/aspeed/rvas/vide + +static void reset_rvas_engine(struct AstRVAS *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); -+ } ++ disable_rvas_engines(pAstRVAS); ++ if (pAstRVAS->config->version == 7) ++ reset_control_deassert(pAstRVAS->rvas_reset); ++ enable_rvas_engines(pAstRVAS); + rvas_init(pAstRVAS); +} + @@ -89125,7 +82032,7 @@ diff --git a/drivers/soc/aspeed/rvas/video_main.c b/drivers/soc/aspeed/rvas/vide +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 2026-04-08 18:03:35.072947026 +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. @@ -89145,7 +82052,7 @@ diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig 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 2026-04-08 18:03:39.964857803 +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 @@ -89156,7 +82063,7 @@ diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile 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 2026-04-08 18:03:48.249706435 +0000 ++++ b/drivers/spi/spi-aspeed-smc.c 2025-12-23 10:16:21.071033558 +0000 @@ -7,10 +7,16 @@ */ @@ -91685,7 +84592,7 @@ 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 2026-04-08 18:03:48.243706544 +0000 ++++ b/drivers/spi/spi-aspeed-txrx.c 2025-12-23 10:16:21.065033658 +0000 @@ -0,0 +1,622 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* @@ -92311,8 +85218,8 @@ diff --git a/drivers/spi/spi-aspeed-txrx.c b/drivers/spi/spi-aspeed-txrx.c + 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 2026-04-08 18:03:48.129708627 +0000 -@@ -0,0 +1,545 @@ ++++ b/drivers/tty/serial/8250/8250_aspeed.c 2025-12-23 10:16:20.962035385 +0000 +@@ -0,0 +1,524 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) ASPEED Technology Inc. @@ -92329,7 +85236,6 @@ diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/825 +#include +#include +#include -+#include +#include +#include +#include @@ -92356,6 +85262,7 @@ 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; @@ -92370,14 +85277,14 @@ diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/825 +struct ast8250_udma { + u32 ch; + -+ u32 tx_rbsz; -+ u32 rx_rbsz; ++ u32 tx_fifosz; ++ u32 rx_fifosz; + + dma_addr_t tx_addr; + dma_addr_t rx_addr; + -+ struct tty_port *tport; -+ struct circ_buf *rx_rb; ++ struct kfifo *tx_fifo; ++ struct kfifo *rx_fifo; + + bool tx_tmout_dis; + bool rx_tmout_dis; @@ -92386,7 +85293,6 @@ 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; @@ -92399,76 +85305,62 @@ 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_rb_rptr, void *id) ++static void ast8250_dma_tx_complete(int tx_fifo_rptr, void *id) +{ -+ unsigned long flags; -+ struct uart_port *port = id; ++ unsigned long flags; ++ struct uart_port *port = (struct uart_port*)id; + struct ast8250_data *data = port->private_data; -+ unsigned int count, tail; ++ struct kfifo *tx_fifo = data->dma.tx_fifo; ++ unsigned int len; + -+ uart_port_lock_irqsave(port, &flags); ++ spin_lock_irqsave(&port->lock, flags); + -+ 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; ++ len = kfifo_out(tx_fifo, NULL, tx_fifo_rptr); ++ port->icount.tx += len; + -+ if (kfifo_len(&data->dma.tport->xmit_fifo) < WAKEUP_CHARS) ++ if (kfifo_len(tx_fifo) < WAKEUP_CHARS) + uart_write_wakeup(port); + -+ uart_port_unlock_irqrestore(port, flags); ++ spin_unlock_irqrestore(&port->lock, flags); +} + -+static void ast8250_dma_rx_complete(int rx_rb_wptr, void *id) ++static void ast8250_dma_rx_complete(int rx_fifo_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 circ_buf *rx_rb = dma->rx_rb; -+ u32 rx_rbsz = dma->rx_rbsz; -+ u32 count = 0; -+ -+ uart_port_lock_irqsave(up, &flags); ++ struct kfifo *rx_fifo = dma->rx_fifo; ++ u32 len = 0; ++ u8 buf[128]; + -+ rx_rb->head = rx_rb_wptr; ++ spin_lock_irqsave(&up->lock, flags); + + dma_sync_single_for_cpu(up->dev, -+ dma->rx_addr, dma->rx_rbsz, DMA_FROM_DEVICE); ++ dma->rx_addr, dma->rx_fifosz, 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; -+ -+ up->icount.rx += count; ++ 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; + } + -+ if (count) { -+ aspeed_udma_set_rx_rptr(data->dma.ch, rx_rb->tail); -+ tty_flip_buffer_push(tp); -+ } ++ tty_flip_buffer_push(tp); + -+ uart_port_unlock_irqrestore(up, flags); ++ spin_unlock_irqrestore(&up->lock, flags); +} + +static void ast8250_dma_start_tx(struct uart_port *port) +{ + struct ast8250_data *data = port->private_data; + struct ast8250_udma *dma = &data->dma; -+ typeof(&dma->tport->xmit_fifo) tmp = &dma->tport->xmit_fifo; -+ struct __kfifo *tx_rb = &tmp->kfifo; ++ struct kfifo *tx_fifo = dma->tx_fifo; + + dma_sync_single_for_device(port->dev, -+ dma->tx_addr, dma->tx_rbsz, DMA_TO_DEVICE); ++ dma->tx_addr, dma->tx_fifosz, DMA_TO_DEVICE); + -+ aspeed_udma_set_tx_wptr(dma->ch, tx_rb->in); ++ aspeed_udma_set_tx_wptr(dma->ch, kfifo_len(tx_fifo)); +} + +static void ast8250_dma_pops_hook(struct uart_port *port) @@ -92562,53 +85454,49 @@ 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_rbsz = UART_XMIT_SIZE; -+ dma->rx_rbsz = DMA_RX_BUFSZ; ++ dma->tx_fifosz = DMA_TX_BUFSZ; ++ dma->rx_fifosz = DMA_RX_BUFSZ; + -+ /* -+ * 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"); ++ if (kfifo_alloc(dma->tx_fifo, dma->tx_fifosz, GFP_KERNEL)) { ++ dev_err(port->dev, "failed to allocate TX DMA ring buffer\n"); + rc = -ENOMEM; + goto out; + } + -+ dma->tx_addr = dma_map_single(port->dev, dma->tport->xmit_buf, -+ dma->tx_rbsz, DMA_TO_DEVICE); ++ 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); + 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_dma_n_out; ++ goto free_rx_fifo; + } + -+ dma->rx_addr = dma_map_single(port->dev, dma->rx_rb->buf, -+ dma->rx_rbsz, DMA_FROM_DEVICE); ++ dma->rx_addr = dma_map_single(port->dev, dma->rx_fifo->kfifo.data, ++ dma->rx_fifosz, 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_dma_n_out; ++ goto free_rx_fifo; + } + + rc = aspeed_udma_request_tx_chan(dma->ch, dma->tx_addr, -+ dma->tx_rbsz, ast8250_dma_tx_complete, port, dma->tx_tmout_dis); ++ dma->tx_fifo, dma->tx_fifosz, ast8250_dma_tx_complete, port, dma->tx_tmout_dis); + if (rc) { + dev_err(port->dev, "failed to request DMA TX channel\n"); -+ goto free_dma_n_out; ++ goto free_rx_fifo; + } + + rc = aspeed_udma_request_rx_chan(dma->ch, dma->rx_addr, -+ dma->rx_rbsz, ast8250_dma_rx_complete, port, dma->rx_tmout_dis); ++ dma->rx_fifo, dma->rx_fifosz, ast8250_dma_rx_complete, port, dma->rx_tmout_dis); + if (rc) { + dev_err(port->dev, "failed to request DMA RX channel\n"); -+ goto free_dma_n_out; ++ goto free_rx_fifo; + } + + ast8250_dma_pops_hook(port); @@ -92620,8 +85508,12 @@ 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_dma_n_out: -+ kfree(dma->rx_rb->buf); ++free_rx_fifo: ++ kfifo_free(dma->rx_fifo); ++ ++free_tx_fifo: ++ kfifo_free(dma->tx_fifo); ++ +out: + return rc; +} @@ -92650,12 +85542,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_rbsz, DMA_TO_DEVICE); ++ dma->tx_fifosz, DMA_TO_DEVICE); + dma_unmap_single(port->dev, dma->rx_addr, -+ dma->rx_rbsz, DMA_FROM_DEVICE); ++ dma->rx_fifosz, DMA_FROM_DEVICE); + -+ if (dma->rx_rb->buf) -+ kfree(dma->rx_rb->buf); ++ kfree(dma->tx_fifo); ++ kfree(dma->rx_fifo); + } + + if (data->is_vuart) @@ -92678,19 +85570,46 @@ diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/825 + return 0; +} + -+static int ast8250_probe_of(struct platform_device *pdev, struct uart_port *p, -+ struct ast8250_data *data) ++static int ast8250_probe(struct platform_device *pdev) +{ -+ struct device *dev = &pdev->dev; + 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; ++ } + -+ data->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!data->res) { ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (res == NULL) { + dev_err(dev, "failed to get register base\n"); + return -ENODEV; + } + -+ data->regs = devm_ioremap(dev, data->res->start, resource_size(data->res)); ++ data->regs = devm_ioremap(dev, res->start, resource_size(res)); + if (IS_ERR(data->regs)) { + dev_err(dev, "failed to map registers\n"); + return PTR_ERR(data->regs); @@ -92702,12 +85621,18 @@ 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"); @@ -92730,10 +85655,17 @@ 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"); @@ -92742,73 +85674,27 @@ 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->mapbase = data->res->start; -+ port->mapsize = resource_size(data->res); ++ 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->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"); @@ -92824,12 +85710,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 = { @@ -92860,7 +85746,7 @@ diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/825 +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 2026-04-08 18:03:34.152963806 +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. @@ -92879,7 +85765,7 @@ diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig 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 2026-04-08 18:03:38.836878376 +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 @@ -92890,7 +85776,7 @@ diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile 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 2026-04-08 18:03:34.751952881 +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. @@ -92906,7 +85792,7 @@ diff --git a/drivers/ufs/host/Kconfig b/drivers/ufs/host/Kconfig + 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 2026-04-08 18:03:39.631863876 +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 @@ -92914,7 +85800,7 @@ diff --git a/drivers/ufs/host/Makefile b/drivers/ufs/host/Makefile +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 2026-04-08 18:03:48.204707257 +0000 ++++ b/drivers/ufs/host/ufs-aspeed.c 2025-12-23 10:16:21.026034312 +0000 @@ -0,0 +1,425 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (C) 2019 ASPEED Technology Inc. */ @@ -93343,7 +86229,7 @@ diff --git a/drivers/ufs/host/ufs-aspeed.c b/drivers/ufs/host/ufs-aspeed.c +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 2026-04-08 18:03:48.336704845 +0000 ++++ b/drivers/usb/gadget/udc/aspeed-vhub/Kconfig 2025-12-23 10:16:21.160032066 +0000 @@ -4,5 +4,6 @@ depends on ARCH_ASPEED || COMPILE_TEST depends on USB_LIBCOMPOSITE @@ -93355,7 +86241,7 @@ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/Kconfig b/drivers/usb/gadget/udc + 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 2026-04-08 18:03:48.336704845 +0000 ++++ b/drivers/usb/gadget/udc/aspeed-vhub/core.c 2025-12-23 10:16:21.160032066 +0000 @@ -23,9 +23,27 @@ #include #include @@ -93384,19 +86270,15 @@ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/ void ast_vhub_done(struct ast_vhub_ep *ep, struct ast_vhub_req *req, int status) { -@@ -239,6 +257,11 @@ +@@ -239,6 +257,7 @@ 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 +276,52 @@ +@@ -253,6 +272,52 @@ vhub->regs + AST_VHUB_IER); } @@ -93449,7 +86331,7 @@ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/ static void ast_vhub_remove(struct platform_device *pdev) { struct ast_vhub *vhub = platform_get_drvdata(pdev); -@@ -280,6 +349,9 @@ +@@ -280,6 +345,9 @@ if (vhub->clk) clk_disable_unprepare(vhub->clk); @@ -93459,7 +86341,7 @@ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/ spin_unlock_irqrestore(&vhub->lock, flags); if (vhub->ep0_bufs) -@@ -291,6 +363,61 @@ +@@ -291,6 +359,61 @@ vhub->ep0_bufs = NULL; } @@ -93521,7 +86403,7 @@ 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 +425,19 @@ +@@ -298,11 +421,19 @@ struct resource *res; int i, rc = 0; const struct device_node *np = pdev->dev.of_node; @@ -93541,16 +86423,7 @@ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/ rc = of_property_read_u32(np, "aspeed,vhub-downstream-ports", &vhub->max_ports); if (rc < 0) -@@ -323,6 +458,8 @@ - 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, -@@ -337,6 +474,13 @@ +@@ -337,6 +468,13 @@ platform_set_drvdata(pdev, vhub); @@ -93564,7 +86437,7 @@ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/ vhub->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(vhub->clk)) { rc = PTR_ERR(vhub->clk); -@@ -348,6 +492,28 @@ +@@ -348,6 +486,28 @@ goto err; } @@ -93593,7 +86466,7 @@ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/ /* 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 +536,12 @@ +@@ -370,6 +530,12 @@ goto err; } @@ -93606,7 +86479,7 @@ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/ /* * Allocate DMA buffers for all EP0s in one chunk, * one per port and one for the vHub itself -@@ -412,15 +584,86 @@ +@@ -412,15 +578,86 @@ return rc; } @@ -93695,7 +86568,7 @@ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/ }; 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 2026-04-08 18:03:48.336704845 +0000 ++++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c 2025-12-23 10:16:21.160032066 +0000 @@ -116,10 +116,14 @@ if (wValue == USB_DEVICE_REMOTE_WAKEUP) { @@ -93724,7 +86597,7 @@ 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 2026-04-08 18:03:48.336704845 +0000 ++++ b/drivers/usb/gadget/udc/aspeed-vhub/epn.c 2025-12-23 10:16:21.160032066 +0000 @@ -340,7 +340,9 @@ struct ast_vhub *vhub = ep->vhub; unsigned long flags; @@ -93827,7 +86700,7 @@ 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 2026-04-08 18:03:48.336704845 +0000 ++++ b/drivers/usb/gadget/udc/aspeed-vhub/hub.c 2025-12-23 10:16:21.160032066 +0000 @@ -221,9 +221,8 @@ EPDBG(ep, "Hub remote wakeup %s\n", is_set ? "enabled" : "disabled"); @@ -93874,16 +86747,8 @@ 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 2026-04-08 18:03:48.336704845 +0000 -@@ -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) -@@ -199,6 +200,14 @@ ++++ b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h 2025-12-23 10:16:21.160032066 +0000 +@@ -199,6 +199,14 @@ #define VHUB_DSC1_IN_SET_LEN(x) ((x) & 0xfff) #define VHUB_DSC1_IN_LEN(x) ((x) & 0xfff) @@ -93898,7 +86763,7 @@ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h b/drivers/usb/gadget/udc/ /**************************************** * * * Data structures and misc definitions * -@@ -218,6 +227,8 @@ +@@ -218,6 +226,8 @@ * values are 256 and 32) */ @@ -93907,7 +86772,7 @@ 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 +399,8 @@ +@@ -388,6 +398,8 @@ spinlock_t lock; struct work_struct wake_work; struct clk *clk; @@ -93916,13 +86781,8 @@ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h b/drivers/usb/gadget/udc/ /* EP0 DMA buffers allocated in one chunk */ void *ep0_bufs; -@@ -417,8 +430,12 @@ - /* Force full speed only */ - bool force_usb1 : 1; +@@ -419,6 +431,7 @@ -+ /* Enlarge FIFO for ast2700 soc0 vhub1 */ -+ bool enlarge_fifo : 1; -+ /* Upstream bus speed captured at bus reset */ unsigned int speed; + u8 current_config; @@ -93931,7 +86791,7 @@ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h b/drivers/usb/gadget/udc/ 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 2026-04-08 18:03:48.296705576 +0000 ++++ b/drivers/usb/gadget/udc/aspeed_udc.c 2025-12-23 10:16:21.115032820 +0000 @@ -156,7 +156,7 @@ #define AST_EP_DMA_DESC_PID_DATA1 (2 << 14) #define AST_EP_DMA_DESC_PID_MDATA (3 << 14) @@ -94124,7 +86984,7 @@ diff --git a/drivers/usb/gadget/udc/aspeed_udc.c b/drivers/usb/gadget/udc/aspeed 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 2026-04-08 18:03:48.256706307 +0000 ++++ b/drivers/watchdog/aspeed_wdt.c 2025-12-23 10:16:21.077033457 +0000 @@ -35,6 +35,8 @@ u32 irq_shift; u32 irq_mask; @@ -94357,7 +87217,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 2026-04-08 18:03:48.454702689 +0000 ++++ b/include/dt-bindings/clock/aspeed,ast1700-clk.h 2025-12-23 10:16:21.275030139 +0000 @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* @@ -94458,7 +87318,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 2026-04-08 18:03:48.463702525 +0000 ++++ b/include/dt-bindings/clock/aspeed,ast1800-clk.h 2025-12-23 10:16:21.285029971 +0000 @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* @@ -94566,7 +87426,7 @@ 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 2026-04-08 18:03:48.468702433 +0000 ++++ b/include/dt-bindings/clock/aspeed,ast2700-scu.h 2025-12-23 10:16:21.289029904 +0000 @@ -0,0 +1,167 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* @@ -94737,7 +87597,7 @@ diff --git a/include/dt-bindings/clock/aspeed,ast2700-scu.h b/include/dt-binding +#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 2026-04-08 18:03:48.459702598 +0000 ++++ b/include/dt-bindings/clock/aspeed-clock.h 2025-12-23 10:16:21.280030055 +0000 @@ -53,5 +53,6 @@ #define ASPEED_RESET_AHB 8 #define ASPEED_RESET_CRT1 9 @@ -94747,7 +87607,7 @@ 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 2026-04-08 18:03:48.473702342 +0000 ++++ b/include/dt-bindings/clock/ast2600-clock.h 2025-12-23 10:16:21.294029820 +0000 @@ -72,7 +72,7 @@ #define ASPEED_CLK_D1CLK 55 #define ASPEED_CLK_VCLK 56 @@ -94793,7 +87653,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 2026-04-08 18:03:48.478702251 +0000 ++++ b/include/dt-bindings/interrupt-controller/aspeed-e2m-ic.h 2025-12-23 10:16:21.299029736 +0000 @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* @@ -94818,7 +87678,7 @@ 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 2026-04-08 18:03:48.483702159 +0000 ++++ b/include/dt-bindings/interrupt-controller/aspeed-scu-ic.h 2025-12-23 10:16:21.304029653 +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 @@ -94840,7 +87700,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 2026-04-08 18:03:48.497701904 +0000 ++++ b/include/dt-bindings/reset/aspeed,ast1700-reset.h 2025-12-23 10:16:21.317029435 +0000 @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* @@ -94913,7 +87773,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 2026-04-08 18:03:48.507701721 +0000 ++++ b/include/dt-bindings/reset/aspeed,ast1800-reset.h 2025-12-23 10:16:21.326029284 +0000 @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* @@ -94978,7 +87838,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 2026-04-08 18:03:48.502701812 +0000 ++++ b/include/dt-bindings/reset/aspeed,ast2700-scu.h 2025-12-23 10:16:21.322029351 +0000 @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* @@ -95107,7 +87967,7 @@ 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 2026-04-08 18:03:48.493701977 +0000 ++++ b/include/dt-bindings/watchdog/aspeed-wdt.h 2025-12-23 10:16:21.313029502 +0000 @@ -89,4 +89,142 @@ #define AST2600_WDT_RESET2_DEFAULT 0x03fffff1 @@ -95253,7 +88113,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 2026-04-08 18:03:48.444702872 +0000 ++++ b/include/linux/aspeed-mctp.h 2025-12-23 10:16:21.266030290 +0000 @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* Copyright (c) 2025 ASPEED Tech */ @@ -95414,7 +88274,7 @@ diff --git a/include/linux/aspeed-mctp.h b/include/linux/aspeed-mctp.h +#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 2026-04-08 18:03:49.279687616 +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)) @@ -95442,7 +88302,7 @@ diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h * @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 2026-04-08 18:03:49.251688128 +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 */ +/* @@ -95482,7 +88342,7 @@ diff --git a/include/linux/mctp-pcie-vdm.h b/include/linux/mctp-pcie-vdm.h +#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 2026-04-08 18:03:49.312687013 +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) @@ -95495,7 +88355,7 @@ diff --git a/include/linux/pwm.h b/include/linux/pwm.h 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 2026-04-08 18:03:48.435703036 +0000 ++++ b/include/linux/soc/aspeed/aspeed-otp.h 2025-12-23 10:16:21.257030440 +0000 @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */ +/* @@ -95511,12 +88371,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 2026-04-08 18:03:48.430703128 +0000 -@@ -0,0 +1,26 @@ ++++ b/include/linux/soc/aspeed/aspeed-udma.h 2025-12-23 10:16:21.252030524 +0000 +@@ -0,0 +1,28 @@ +#ifndef __ASPEED_UDMA_H__ +#define __ASPEED_UDMA_H__ + -+typedef void (*aspeed_udma_cb_t)(int rb_rwptr, void *id); ++typedef void (*aspeed_udma_cb_t)(int fifo_rwptr, void *id); + +enum aspeed_udma_ops { + ASPEED_UDMA_OP_ENABLE, @@ -95530,9 +88390,11 @@ 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, u32 rb_sz, ++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 en_tmout); -+int aspeed_udma_request_rx_chan(u32 ch_no, dma_addr_t addr, u32 rb_sz, ++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 en_tmout); + +int aspeed_udma_free_tx_chan(u32 ch_no); @@ -95541,7 +88403,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 2026-04-08 18:03:48.391703840 +0000 ++++ b/include/soc/aspeed/reset-aspeed.h 2025-12-23 10:16:21.214031161 +0000 @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* @@ -95566,7 +88428,7 @@ diff --git a/include/soc/aspeed/reset-aspeed.h b/include/soc/aspeed/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 2026-04-08 18:03:49.268687817 +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 */ + @@ -95696,7 +88558,7 @@ diff --git a/include/trace/events/xdma.h b/include/trace/events/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 2026-04-08 18:03:48.425703219 +0000 ++++ b/include/uapi/linux/aspeed-mctp.h 2025-12-23 10:16:21.247030608 +0000 @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* Copyright (c) 2020 Intel Corporation */ @@ -95836,7 +88698,7 @@ 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 2026-04-08 18:03:48.401703657 +0000 ++++ b/include/uapi/linux/aspeed-video.h 2025-12-23 10:16:21.223031010 +0000 @@ -8,6 +8,15 @@ #include @@ -95855,7 +88717,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 2026-04-08 18:03:48.410703493 +0000 ++++ b/include/uapi/linux/aspeed-xdma.h 2025-12-23 10:16:21.233030843 +0000 @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* Copyright IBM Corp 2019 */ @@ -95901,7 +88763,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 2026-04-08 18:03:48.415703402 +0000 ++++ b/include/uapi/linux/otp_ast2600.h 2025-12-23 10:16:21.238030759 +0000 @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */ +/* @@ -95944,7 +88806,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 2026-04-08 18:03:48.396703749 +0000 ++++ b/include/uapi/linux/otp_ast2700.h 2025-12-23 10:16:21.218031094 +0000 @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */ +/* @@ -95995,7 +88857,7 @@ diff --git a/include/uapi/linux/otp_ast2700.h b/include/uapi/linux/otp_ast2700.h +#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 2026-04-08 18:03:49.290687415 +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 From df6ffa0198eb43ce3d47fc3e1625547a311664a3 Mon Sep 17 00:00:00 2001 From: Roger Liao Date: Wed, 13 May 2026 23:16:13 +0000 Subject: [PATCH 2/2] Split 00.07.02 update into aspeed and vendor independent patches Signed-off-by: Roger Liao --- ...only-changes-update-to-6.12-00.07.02.patch | 15451 ++++++++++++++++ ...dent-changes-update-to-6.12-00.07.02.patch | 2234 +++ patches-sonic/series | 2 + 3 files changed, 17687 insertions(+) create mode 100644 patches-sonic/aspeed-ast2700-aspeed-only-changes-update-to-6.12-00.07.02.patch create mode 100644 patches-sonic/aspeed-ast2700-vendor-independent-changes-update-to-6.12-00.07.02.patch diff --git a/patches-sonic/aspeed-ast2700-aspeed-only-changes-update-to-6.12-00.07.02.patch b/patches-sonic/aspeed-ast2700-aspeed-only-changes-update-to-6.12-00.07.02.patch new file mode 100644 index 000000000..836a3e133 --- /dev/null +++ b/patches-sonic/aspeed-ast2700-aspeed-only-changes-update-to-6.12-00.07.02.patch @@ -0,0 +1,15451 @@ +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,6 +84,7 @@ 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_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/aspeed-ast2700-vendor-independent-changes-update-to-6.12-00.07.02.patch b/patches-sonic/aspeed-ast2700-vendor-independent-changes-update-to-6.12-00.07.02.patch new file mode 100644 index 000000000..7e5c3fde8 --- /dev/null +++ b/patches-sonic/aspeed-ast2700-vendor-independent-changes-update-to-6.12-00.07.02.patch @@ -0,0 +1,2234 @@ +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/char/hw_random/Kconfig | 1 - + drivers/clk/Kconfig | 8 - + drivers/clk/Makefile | 1 - + drivers/edac/altera_edac.c | 1 + + drivers/edac/edac_mc_sysfs.c | 24 - + drivers/edac/i10nm_base.c | 14 - + drivers/edac/synopsys_edac.c | 97 +-- + drivers/gpio/gpio-aspeed-sgpio.c | 749 ++++++------------- + drivers/i3c/master/ast2600-i3c-master.c | 34 +- + drivers/irqchip/Kconfig | 3 + + drivers/irqchip/Makefile | 2 + + 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/reset/Kconfig | 11 +- + drivers/rtc/rtc-aspeed.c | 22 +- + drivers/usb/gadget/udc/aspeed-vhub/core.c | 6 + + drivers/usb/gadget/udc/aspeed-vhub/vhub.h | 4 + + 19 files changed, 830 insertions(+), 630 deletions(-) + +diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig +index d723621e4..dd2e0f031 100644 +--- a/drivers/char/hw_random/Kconfig ++++ b/drivers/char/hw_random/Kconfig +@@ -286,7 +286,6 @@ config HW_RANDOM_INGENIC_TRNG + config HW_RANDOM_NOMADIK + tristate "ST-Ericsson Nomadik Random Number Generator support" + depends on ARCH_NOMADIK || COMPILE_TEST +- depends on ARM_AMBA + default HW_RANDOM + help + This driver provides kernel-side support for the Random Number +diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig +index fb3e94edc..ddded0fbc 100644 +--- a/drivers/clk/Kconfig ++++ b/drivers/clk/Kconfig +@@ -356,14 +356,6 @@ config COMMON_CLK_LOCHNAGAR + This driver supports the clocking features of the Cirrus Logic + Lochnagar audio development board. + +-config COMMON_CLK_NPCM8XX +- tristate "Clock driver for the NPCM8XX SoC Family" +- depends on ARCH_NPCM || COMPILE_TEST +- help +- This driver supports the clocks on the Nuvoton BMC NPCM8XX SoC Family, +- all the clocks are initialized by the bootloader, so this driver +- allows only reading of current settings directly from the hardware. +- + config COMMON_CLK_LOONGSON2 + bool "Clock driver for Loongson-2 SoC" + depends on LOONGARCH || COMPILE_TEST +diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile +index 0a8016c2e..ea0e812f7 100644 +--- a/drivers/clk/Makefile ++++ b/drivers/clk/Makefile +@@ -64,7 +64,6 @@ obj-$(CONFIG_ARCH_MILBEAUT_M10V) += clk-milbeaut.o + obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o + obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o + obj-$(CONFIG_ARCH_NPCM7XX) += clk-npcm7xx.o +-obj-$(CONFIG_COMMON_CLK_NPCM8XX) += clk-npcm8xx.o + obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o + obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o + obj-$(CONFIG_CLK_LS1028A_PLLDIG) += clk-plldig.o +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/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c +index ec3ed5e2b..d7416166f 100644 +--- a/drivers/edac/synopsys_edac.c ++++ b/drivers/edac/synopsys_edac.c +@@ -332,26 +332,20 @@ struct synps_edac_priv { + #endif + }; + +-enum synps_platform_type { +- ZYNQ, +- ZYNQMP, +- SYNPS, +-}; +- + /** + * struct synps_platform_data - synps platform data structure. +- * @platform: Identifies the target hardware platform + * @get_error_info: Get EDAC error info. + * @get_mtype: Get mtype. + * @get_dtype: Get dtype. ++ * @get_ecc_state: Get ECC state. + * @get_mem_info: Get EDAC memory info + * @quirks: To differentiate IPs. + */ + struct synps_platform_data { +- enum synps_platform_type platform; + int (*get_error_info)(struct synps_edac_priv *priv); + enum mem_type (*get_mtype)(const void __iomem *base); + enum dev_type (*get_dtype)(const void __iomem *base); ++ bool (*get_ecc_state)(void __iomem *base); + #ifdef CONFIG_EDAC_DEBUG + u64 (*get_mem_info)(struct synps_edac_priv *priv); + #endif +@@ -726,38 +720,51 @@ static enum dev_type zynqmp_get_dtype(const void __iomem *base) + return dt; + } + +-static bool get_ecc_state(struct synps_edac_priv *priv) ++/** ++ * zynq_get_ecc_state - Return the controller ECC enable/disable status. ++ * @base: DDR memory controller base address. ++ * ++ * Get the ECC enable/disable status of the controller. ++ * ++ * Return: true if enabled, otherwise false. ++ */ ++static bool zynq_get_ecc_state(void __iomem *base) + { +- u32 ecctype, clearval; + enum dev_type dt; ++ u32 ecctype; + +- if (priv->p_data->platform == ZYNQ) { +- dt = zynq_get_dtype(priv->baseaddr); +- if (dt == DEV_UNKNOWN) +- return false; +- +- ecctype = readl(priv->baseaddr + SCRUB_OFST) & SCRUB_MODE_MASK; +- if (ecctype == SCRUB_MODE_SECDED && dt == DEV_X2) { +- clearval = ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_UE_ERR; +- writel(clearval, priv->baseaddr + ECC_CTRL_OFST); +- writel(0x0, priv->baseaddr + ECC_CTRL_OFST); +- return true; +- } +- } else { +- dt = zynqmp_get_dtype(priv->baseaddr); +- if (dt == DEV_UNKNOWN) +- return false; +- +- ecctype = readl(priv->baseaddr + ECC_CFG0_OFST) & SCRUB_MODE_MASK; +- if (ecctype == SCRUB_MODE_SECDED && +- (dt == DEV_X2 || dt == DEV_X4 || dt == DEV_X8)) { +- clearval = readl(priv->baseaddr + ECC_CLR_OFST) | +- ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_CE_ERRCNT | +- ECC_CTRL_CLR_UE_ERR | ECC_CTRL_CLR_UE_ERRCNT; +- writel(clearval, priv->baseaddr + ECC_CLR_OFST); +- return true; +- } +- } ++ dt = zynq_get_dtype(base); ++ if (dt == DEV_UNKNOWN) ++ return false; ++ ++ ecctype = readl(base + SCRUB_OFST) & SCRUB_MODE_MASK; ++ if ((ecctype == SCRUB_MODE_SECDED) && (dt == DEV_X2)) ++ return true; ++ ++ return false; ++} ++ ++/** ++ * zynqmp_get_ecc_state - Return the controller ECC enable/disable status. ++ * @base: DDR memory controller base address. ++ * ++ * Get the ECC enable/disable status for the controller. ++ * ++ * Return: a ECC status boolean i.e true/false - enabled/disabled. ++ */ ++static bool zynqmp_get_ecc_state(void __iomem *base) ++{ ++ enum dev_type dt; ++ u32 ecctype; ++ ++ dt = zynqmp_get_dtype(base); ++ if (dt == DEV_UNKNOWN) ++ return false; ++ ++ ecctype = readl(base + ECC_CFG0_OFST) & SCRUB_MODE_MASK; ++ if ((ecctype == SCRUB_MODE_SECDED) && ++ ((dt == DEV_X2) || (dt == DEV_X4) || (dt == DEV_X8))) ++ return true; + + return false; + } +@@ -927,18 +934,18 @@ static int setup_irq(struct mem_ctl_info *mci, + } + + static const struct synps_platform_data zynq_edac_def = { +- .platform = ZYNQ, + .get_error_info = zynq_get_error_info, + .get_mtype = zynq_get_mtype, + .get_dtype = zynq_get_dtype, ++ .get_ecc_state = zynq_get_ecc_state, + .quirks = 0, + }; + + static const struct synps_platform_data zynqmp_edac_def = { +- .platform = ZYNQMP, + .get_error_info = zynqmp_get_error_info, + .get_mtype = zynqmp_get_mtype, + .get_dtype = zynqmp_get_dtype, ++ .get_ecc_state = zynqmp_get_ecc_state, + #ifdef CONFIG_EDAC_DEBUG + .get_mem_info = zynqmp_get_mem_info, + #endif +@@ -950,10 +957,10 @@ static const struct synps_platform_data zynqmp_edac_def = { + }; + + static const struct synps_platform_data synopsys_edac_def = { +- .platform = SYNPS, + .get_error_info = zynqmp_get_error_info, + .get_mtype = zynqmp_get_mtype, + .get_dtype = zynqmp_get_dtype, ++ .get_ecc_state = zynqmp_get_ecc_state, + .quirks = (DDR_ECC_INTR_SUPPORT | DDR_ECC_INTR_SELF_CLEAR + #ifdef CONFIG_EDAC_DEBUG + | DDR_ECC_DATA_POISON_SUPPORT +@@ -1383,6 +1390,10 @@ static int mc_probe(struct platform_device *pdev) + if (!p_data) + return -ENODEV; + ++ if (!p_data->get_ecc_state(baseaddr)) { ++ edac_printk(KERN_INFO, EDAC_MC, "ECC not enabled\n"); ++ return -ENXIO; ++ } + + layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; + layers[0].size = SYNPS_EDAC_NR_CSROWS; +@@ -1402,12 +1413,6 @@ static int mc_probe(struct platform_device *pdev) + priv = mci->pvt_info; + priv->baseaddr = baseaddr; + priv->p_data = p_data; +- if (!get_ecc_state(priv)) { +- edac_printk(KERN_INFO, EDAC_MC, "ECC not enabled\n"); +- rc = -ENODEV; +- goto free_edac_mc; +- } +- + spin_lock_init(&priv->reglock); + + mc_init(mci, pdev); +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/irqchip/Makefile b/drivers/irqchip/Makefile +index 95e13a5b2..56c98f5dd 100644 +--- a/drivers/irqchip/Makefile ++++ b/drivers/irqchip/Makefile +@@ -83,6 +83,8 @@ obj-$(CONFIG_MVEBU_PIC) += irq-mvebu-pic.o + 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_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 +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/reset/Kconfig b/drivers/reset/Kconfig +index 0158fba2a..bfa791c92 100644 +--- a/drivers/reset/Kconfig ++++ b/drivers/reset/Kconfig +@@ -58,8 +58,8 @@ config RESET_BERLIN + + config RESET_BRCMSTB + tristate "Broadcom STB reset controller" +- depends on ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST +- default ARCH_BRCMSTB || ARCH_BCM2835 ++ depends on ARCH_BRCMSTB || COMPILE_TEST ++ default ARCH_BRCMSTB + help + This enables the reset controller driver for Broadcom STB SoCs using + a SUN_TOP_CTRL_SW_INIT style controller. +@@ -67,11 +67,11 @@ config RESET_BRCMSTB + config RESET_BRCMSTB_RESCAL + tristate "Broadcom STB RESCAL reset controller" + depends on HAS_IOMEM +- depends on ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST +- default ARCH_BRCMSTB || ARCH_BCM2835 ++ depends on ARCH_BRCMSTB || COMPILE_TEST ++ default ARCH_BRCMSTB + help + This enables the RESCAL reset controller for SATA, PCIe0, or PCIe1 on +- BCM7216 or the BCM2712. ++ BCM7216. + + config RESET_EYEQ + bool "Mobileye EyeQ reset controller" +@@ -186,7 +186,6 @@ config RESET_MESON_AUDIO_ARB + config RESET_NPCM + bool "NPCM BMC Reset Driver" if COMPILE_TEST + default ARCH_NPCM +- select AUXILIARY_BUS + help + This enables the reset controller driver for Nuvoton NPCM + BMC SoCs. +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/series b/patches-sonic/series index 4a5415d12..7611f2c2a 100644 --- a/patches-sonic/series +++ b/patches-sonic/series @@ -233,6 +233,8 @@ driver-tty-serial-8250-add-support-for-fintek-F81214E.patch # Linux upstream pen ###-> aspeed aspeed-ast2700-support.patch +aspeed-ast2700-aspeed-only-changes-update-to-6.12-00.07.02.patch +aspeed-ast2700-vendor-independent-changes-update-to-6.12-00.07.02.patch nexthop-b27-dts.patch 0001-Add-device-tree-for-Nokia-BMC-H6-128-platform.patch arista_goldfinch-dts.patch