Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 0/5] Add CPSW2G and CPSW9G nodes for J784S4
From: Chintan Vankar @ 2024-03-29  5:31 UTC (permalink / raw)
  To: Conor Dooley, Krzysztof Kozlowski, Rob Herring, Tero Kristo,
	Vignesh Raghavendra, Nishanth Menon
  Cc: linux-kernel, devicetree, linux-arm-kernel, s-vadapalli,
	Chintan Vankar

This series adds device-tree nodes for CPSW2G and CPSW9G instance
of the CPSW Ethernet Switch on TI's J784S4 SoC. Additionally,
two device-tree overlays are also added:
1. QSGMII mode with the CPSW9G instance via the ENET EXPANSION 1
   connector.
2. USXGMII mode with MAC Ports 1 and 2 of the CPSW9G instance via
   ENET EXPANSION 1 and 2 connectors, configured in fixed-link
   mode of operation at 5Gbps link speed.

Link to v5:
https://lore.kernel.org/r/20240314072129.1520475-1-c-vankar@ti.com/

Changes from v5 to v6:
- Updated order of properties in Device Nodes based on
  https://docs.kernel.org/devicetree/bindings/dts-coding-style.html#order-of-properties-in-device-node

Chintan Vankar (1):
  arm64: dts: ti: k3-j784s4-evm: Add alias for MCU CPSW2G

Siddharth Vadapalli (4):
  arm64: dts: ti: k3-j784s4-main: Add CPSW2G and CPSW9G nodes
  arm64: dts: ti: k3-j784s4-evm: Enable Main CPSW2G node and add aliases
    for it
  arm64: dts: ti: k3-j784s4: Add overlay to enable QSGMII mode with
    CPSW9G
  arm64: dts: ti: k3-j784s4: Add overlay for dual port USXGMII mode

 arch/arm64/boot/dts/ti/Makefile               |  11 +-
 .../ti/k3-j784s4-evm-quad-port-eth-exp1.dtso  | 147 ++++++++++++++
 .../ti/k3-j784s4-evm-usxgmii-exp1-exp2.dtso   |  81 ++++++++
 arch/arm64/boot/dts/ti/k3-j784s4-evm.dts      |  51 +++++
 arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi    | 187 ++++++++++++++++++
 5 files changed, 476 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm64/boot/dts/ti/k3-j784s4-evm-quad-port-eth-exp1.dtso
 create mode 100644 arch/arm64/boot/dts/ti/k3-j784s4-evm-usxgmii-exp1-exp2.dtso

-- 
2.34.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH v6 2/5] arm64: dts: ti: k3-j784s4-main: Add CPSW2G and CPSW9G nodes
From: Chintan Vankar @ 2024-03-29  5:31 UTC (permalink / raw)
  To: Conor Dooley, Krzysztof Kozlowski, Rob Herring, Tero Kristo,
	Vignesh Raghavendra, Nishanth Menon
  Cc: linux-kernel, devicetree, linux-arm-kernel, s-vadapalli,
	Chintan Vankar
In-Reply-To: <20240329053130.2822129-1-c-vankar@ti.com>

From: Siddharth Vadapalli <s-vadapalli@ti.com>

J784S4 SoC has MAIN CPSW2G and CPSW9G instances of the CPSW
Ethernet Switch. CPSW2G has 1 external port and 1 host port
while CPSW9G has 8 external ports and 1 host port.

Add device-tree nodes for MAIN CPSW2G and CPSW9G and disable
them by default. MAIN CPSW2G will be enabled in the board file
while device-tree overlays will be used to enable CPSW9G.

Signed-off-by: Siddharth Vadapalli <s-vadapalli@ti.com>
Signed-off-by: Chintan Vankar <c-vankar@ti.com>
---

Link to v5:
https://lore.kernel.org/r/20240314072129.1520475-3-c-vankar@ti.com/

Changes from v5 to v6:
- Updated order of properties in Device Nodes based on
  https://docs.kernel.org/devicetree/bindings/dts-coding-style.html#order-of-properties-in-device-node

 arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi | 187 +++++++++++++++++++++
 1 file changed, 187 insertions(+)

diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi
index b67c37460a73..7dfa43d25d38 100644
--- a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi
@@ -48,6 +48,19 @@ scm_conf: bus@100000 {
 		#size-cells = <1>;
 		ranges = <0x00 0x00 0x00100000 0x1c000>;
 
+		cpsw1_phy_gmii_sel: phy@4034 {
+			compatible = "ti,am654-phy-gmii-sel";
+			reg = <0x4034 0x4>;
+			#phy-cells = <1>;
+		};
+
+		cpsw0_phy_gmii_sel: phy@4044 {
+			compatible = "ti,j784s4-cpsw9g-phy-gmii-sel";
+			reg = <0x4044 0x20>;
+			#phy-cells = <1>;
+			ti,qsgmii-main-ports = <7>, <7>;
+		};
+
 		serdes_ln_ctrl: mux-controller@4080 {
 			compatible = "reg-mux";
 			reg = <0x00004080 0x30>;
@@ -1439,6 +1452,180 @@ cpts@310d0000 {
 		};
 	};
 
+	main_cpsw0: ethernet@c000000 {
+		compatible = "ti,j784s4-cpswxg-nuss";
+		reg = <0x00 0xc000000 0x00 0x200000>;
+		reg-names = "cpsw_nuss";
+		ranges = <0x00 0x00 0x00 0xc000000 0x00 0x200000>;
+		#address-cells = <2>;
+		#size-cells = <2>;
+		dma-coherent;
+		clocks = <&k3_clks 64 0>;
+		clock-names = "fck";
+		power-domains = <&k3_pds 64 TI_SCI_PD_EXCLUSIVE>;
+
+		dmas = <&main_udmap 0xca00>,
+		       <&main_udmap 0xca01>,
+		       <&main_udmap 0xca02>,
+		       <&main_udmap 0xca03>,
+		       <&main_udmap 0xca04>,
+		       <&main_udmap 0xca05>,
+		       <&main_udmap 0xca06>,
+		       <&main_udmap 0xca07>,
+		       <&main_udmap 0x4a00>;
+		dma-names = "tx0", "tx1", "tx2", "tx3",
+			    "tx4", "tx5", "tx6", "tx7",
+			    "rx";
+
+		status = "disabled";
+
+		ethernet-ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			main_cpsw0_port1: port@1 {
+				reg = <1>;
+				label = "port1";
+				ti,mac-only;
+				status = "disabled";
+			};
+
+			main_cpsw0_port2: port@2 {
+				reg = <2>;
+				label = "port2";
+				ti,mac-only;
+				status = "disabled";
+			};
+
+			main_cpsw0_port3: port@3 {
+				reg = <3>;
+				label = "port3";
+				ti,mac-only;
+				status = "disabled";
+			};
+
+			main_cpsw0_port4: port@4 {
+				reg = <4>;
+				label = "port4";
+				ti,mac-only;
+				status = "disabled";
+			};
+
+			main_cpsw0_port5: port@5 {
+				reg = <5>;
+				label = "port5";
+				ti,mac-only;
+				status = "disabled";
+			};
+
+			main_cpsw0_port6: port@6 {
+				reg = <6>;
+				label = "port6";
+				ti,mac-only;
+				status = "disabled";
+			};
+
+			main_cpsw0_port7: port@7 {
+				reg = <7>;
+				label = "port7";
+				ti,mac-only;
+				status = "disabled";
+			};
+
+			main_cpsw0_port8: port@8 {
+				reg = <8>;
+				label = "port8";
+				ti,mac-only;
+				status = "disabled";
+			};
+		};
+
+		main_cpsw0_mdio: mdio@f00 {
+			compatible = "ti,cpsw-mdio","ti,davinci_mdio";
+			reg = <0x00 0xf00 0x00 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&k3_clks 64 0>;
+			clock-names = "fck";
+			bus_freq = <1000000>;
+			status = "disabled";
+		};
+
+		cpts@3d000 {
+			compatible = "ti,am65-cpts";
+			reg = <0x00 0x3d000 0x00 0x400>;
+			clocks = <&k3_clks 64 3>;
+			clock-names = "cpts";
+			interrupts-extended = <&gic500 GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "cpts";
+			ti,cpts-ext-ts-inputs = <4>;
+			ti,cpts-periodic-outputs = <2>;
+		};
+	};
+
+	main_cpsw1: ethernet@c200000 {
+		compatible = "ti,j721e-cpsw-nuss";
+		reg = <0x00 0xc200000 0x00 0x200000>;
+		reg-names = "cpsw_nuss";
+		ranges = <0x00 0x00 0x00 0xc200000 0x00 0x200000>;
+		#address-cells = <2>;
+		#size-cells = <2>;
+		dma-coherent;
+		clocks = <&k3_clks 62 0>;
+		clock-names = "fck";
+		power-domains = <&k3_pds 62 TI_SCI_PD_EXCLUSIVE>;
+
+		dmas = <&main_udmap 0xc640>,
+			<&main_udmap 0xc641>,
+			<&main_udmap 0xc642>,
+			<&main_udmap 0xc643>,
+			<&main_udmap 0xc644>,
+			<&main_udmap 0xc645>,
+			<&main_udmap 0xc646>,
+			<&main_udmap 0xc647>,
+			<&main_udmap 0x4640>;
+		dma-names = "tx0", "tx1", "tx2", "tx3",
+				"tx4", "tx5", "tx6", "tx7",
+				"rx";
+
+		status = "disabled";
+
+		ethernet-ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			main_cpsw1_port1: port@1 {
+				reg = <1>;
+				label = "port1";
+				phys = <&cpsw1_phy_gmii_sel 1>;
+				ti,mac-only;
+				status = "disabled";
+			};
+		};
+
+		main_cpsw1_mdio: mdio@f00 {
+			compatible = "ti,cpsw-mdio", "ti,davinci_mdio";
+			reg = <0x00 0xf00 0x00 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&k3_clks 62 0>;
+			clock-names = "fck";
+			bus_freq = <1000000>;
+			status = "disabled";
+		};
+
+		cpts@3d000 {
+			compatible = "ti,am65-cpts";
+			reg = <0x00 0x3d000 0x00 0x400>;
+			clocks = <&k3_clks 62 3>;
+			clock-names = "cpts";
+			interrupts-extended = <&gic500 GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "cpts";
+			ti,cpts-ext-ts-inputs = <4>;
+			ti,cpts-periodic-outputs = <2>;
+		};
+	};
+
 	main_mcan0: can@2701000 {
 		compatible = "bosch,m_can";
 		reg = <0x00 0x02701000 0x00 0x200>,
-- 
2.34.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v4 01/15] arch: Add ARCH_HAS_KERNEL_FPU_SUPPORT
From: Samuel Holland @ 2024-03-29  7:18 UTC (permalink / raw)
  To: Andrew Morton, linux-arm-kernel, x86
  Cc: linux-kernel, linux-arch, linuxppc-dev, linux-riscv,
	Christoph Hellwig, loongarch, amd-gfx, Samuel Holland,
	Borislav Petkov, Catalin Marinas, Dave Hansen, Huacai Chen,
	Ingo Molnar, Jonathan Corbet, Masahiro Yamada, Nathan Chancellor,
	Nicolas Schier, Russell King, Thomas Gleixner, Will Deacon,
	linux-doc, linux-kbuild
In-Reply-To: <20240329072441.591471-1-samuel.holland@sifive.com>

Several architectures provide an API to enable the FPU and run
floating-point SIMD code in kernel space. However, the function names,
header locations, and semantics are inconsistent across architectures,
and FPU support may be gated behind other Kconfig options.

Provide a standard way for architectures to declare that kernel space
FPU support is available. Architectures selecting this option must
implement what is currently the most common API (kernel_fpu_begin() and
kernel_fpu_end(), plus a new function kernel_fpu_available()) and
provide the appropriate CFLAGS for compiling floating-point C code.

Suggested-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
---

(no changes since v2)

Changes in v2:
 - Add documentation explaining the built-time and runtime APIs
 - Add a linux/fpu.h header for generic isolation enforcement

 Documentation/core-api/floating-point.rst | 78 +++++++++++++++++++++++
 Documentation/core-api/index.rst          |  1 +
 Makefile                                  |  5 ++
 arch/Kconfig                              |  6 ++
 include/linux/fpu.h                       | 12 ++++
 5 files changed, 102 insertions(+)
 create mode 100644 Documentation/core-api/floating-point.rst
 create mode 100644 include/linux/fpu.h

diff --git a/Documentation/core-api/floating-point.rst b/Documentation/core-api/floating-point.rst
new file mode 100644
index 000000000000..a8d0d4b05052
--- /dev/null
+++ b/Documentation/core-api/floating-point.rst
@@ -0,0 +1,78 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Floating-point API
+==================
+
+Kernel code is normally prohibited from using floating-point (FP) registers or
+instructions, including the C float and double data types. This rule reduces
+system call overhead, because the kernel does not need to save and restore the
+userspace floating-point register state.
+
+However, occasionally drivers or library functions may need to include FP code.
+This is supported by isolating the functions containing FP code to a separate
+translation unit (a separate source file), and saving/restoring the FP register
+state around calls to those functions. This creates "critical sections" of
+floating-point usage.
+
+The reason for this isolation is to prevent the compiler from generating code
+touching the FP registers outside these critical sections. Compilers sometimes
+use FP registers to optimize inlined ``memcpy`` or variable assignment, as
+floating-point registers may be wider than general-purpose registers.
+
+Usability of floating-point code within the kernel is architecture-specific.
+Additionally, because a single kernel may be configured to support platforms
+both with and without a floating-point unit, FPU availability must be checked
+both at build time and at run time.
+
+Several architectures implement the generic kernel floating-point API from
+``linux/fpu.h``, as described below. Some other architectures implement their
+own unique APIs, which are documented separately.
+
+Build-time API
+--------------
+
+Floating-point code may be built if the option ``ARCH_HAS_KERNEL_FPU_SUPPORT``
+is enabled. For C code, such code must be placed in a separate file, and that
+file must have its compilation flags adjusted using the following pattern::
+
+    CFLAGS_foo.o += $(CC_FLAGS_FPU)
+    CFLAGS_REMOVE_foo.o += $(CC_FLAGS_NO_FPU)
+
+Architectures are expected to define one or both of these variables in their
+top-level Makefile as needed. For example::
+
+    CC_FLAGS_FPU := -mhard-float
+
+or::
+
+    CC_FLAGS_NO_FPU := -msoft-float
+
+Normal kernel code is assumed to use the equivalent of ``CC_FLAGS_NO_FPU``.
+
+Runtime API
+-----------
+
+The runtime API is provided in ``linux/fpu.h``. This header cannot be included
+from files implementing FP code (those with their compilation flags adjusted as
+above). Instead, it must be included when defining the FP critical sections.
+
+.. c:function:: bool kernel_fpu_available( void )
+
+        This function reports if floating-point code can be used on this CPU or
+        platform. The value returned by this function is not expected to change
+        at runtime, so it only needs to be called once, not before every
+        critical section.
+
+.. c:function:: void kernel_fpu_begin( void )
+                void kernel_fpu_end( void )
+
+        These functions create a floating-point critical section. It is only
+        valid to call ``kernel_fpu_begin()`` after a previous call to
+        ``kernel_fpu_available()`` returned ``true``. These functions are only
+        guaranteed to be callable from (preemptible or non-preemptible) process
+        context.
+
+        Preemption may be disabled inside critical sections, so their size
+        should be minimized. They are *not* required to be reentrant. If the
+        caller expects to nest critical sections, it must implement its own
+        reference counting.
diff --git a/Documentation/core-api/index.rst b/Documentation/core-api/index.rst
index 7a3a08d81f11..974beccd671f 100644
--- a/Documentation/core-api/index.rst
+++ b/Documentation/core-api/index.rst
@@ -48,6 +48,7 @@ Library functionality that is used throughout the kernel.
    errseq
    wrappers/atomic_t
    wrappers/atomic_bitops
+   floating-point
 
 Low level entry and exit
 ========================
diff --git a/Makefile b/Makefile
index 763b6792d3d5..710f65e4249d 100644
--- a/Makefile
+++ b/Makefile
@@ -964,6 +964,11 @@ KBUILD_CFLAGS	+= $(CC_FLAGS_CFI)
 export CC_FLAGS_CFI
 endif
 
+# Architectures can define flags to add/remove for floating-point support
+CC_FLAGS_FPU	+= -D_LINUX_FPU_COMPILATION_UNIT
+export CC_FLAGS_FPU
+export CC_FLAGS_NO_FPU
+
 ifneq ($(CONFIG_FUNCTION_ALIGNMENT),0)
 # Set the minimal function alignment. Use the newer GCC option
 # -fmin-function-alignment if it is available, or fall back to -falign-funtions.
diff --git a/arch/Kconfig b/arch/Kconfig
index 9f066785bb71..8e34b3acf73d 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -1569,6 +1569,12 @@ config ARCH_HAS_NONLEAF_PMD_YOUNG
 	  address translations. Page table walkers that clear the accessed bit
 	  may use this capability to reduce their search space.
 
+config ARCH_HAS_KERNEL_FPU_SUPPORT
+	bool
+	help
+	  Architectures that select this option can run floating-point code in
+	  the kernel, as described in Documentation/core-api/floating-point.rst.
+
 source "kernel/gcov/Kconfig"
 
 source "scripts/gcc-plugins/Kconfig"
diff --git a/include/linux/fpu.h b/include/linux/fpu.h
new file mode 100644
index 000000000000..2fb63e22913b
--- /dev/null
+++ b/include/linux/fpu.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _LINUX_FPU_H
+#define _LINUX_FPU_H
+
+#ifdef _LINUX_FPU_COMPILATION_UNIT
+#error FP code must be compiled separately. See Documentation/core-api/floating-point.rst.
+#endif
+
+#include <asm/fpu.h>
+
+#endif
-- 
2.44.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v4 03/15] ARM: crypto: Use CC_FLAGS_FPU for NEON CFLAGS
From: Samuel Holland @ 2024-03-29  7:18 UTC (permalink / raw)
  To: Andrew Morton, linux-arm-kernel, x86
  Cc: linux-kernel, linux-arch, linuxppc-dev, linux-riscv,
	Christoph Hellwig, loongarch, amd-gfx, Samuel Holland,
	Russell King
In-Reply-To: <20240329072441.591471-1-samuel.holland@sifive.com>

Now that CC_FLAGS_FPU is exported and can be used anywhere in the source
tree, use it instead of duplicating the flags here.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
---

(no changes since v1)

 arch/arm/lib/Makefile | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index 650404be6768..0ca5aae1bcc3 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -40,8 +40,7 @@ $(obj)/csumpartialcopy.o:	$(obj)/csumpartialcopygeneric.S
 $(obj)/csumpartialcopyuser.o:	$(obj)/csumpartialcopygeneric.S
 
 ifeq ($(CONFIG_KERNEL_MODE_NEON),y)
-  NEON_FLAGS			:= -march=armv7-a -mfloat-abi=softfp -mfpu=neon
-  CFLAGS_xor-neon.o		+= $(NEON_FLAGS)
+  CFLAGS_xor-neon.o		+= $(CC_FLAGS_FPU)
   obj-$(CONFIG_XOR_BLOCKS)	+= xor-neon.o
 endif
 
-- 
2.44.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v4 04/15] arm64: Implement ARCH_HAS_KERNEL_FPU_SUPPORT
From: Samuel Holland @ 2024-03-29  7:18 UTC (permalink / raw)
  To: Andrew Morton, linux-arm-kernel, x86
  Cc: linux-kernel, linux-arch, linuxppc-dev, linux-riscv,
	Christoph Hellwig, loongarch, amd-gfx, Samuel Holland,
	Catalin Marinas, Will Deacon
In-Reply-To: <20240329072441.591471-1-samuel.holland@sifive.com>

arm64 provides an equivalent to the common kernel-mode FPU API, but in a
different header and using different function names. Add a wrapper
header, and export CFLAGS adjustments as found in lib/raid6/Makefile.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
---

(no changes since v2)

Changes in v2:
 - Remove file name from header comment

 arch/arm64/Kconfig           |  1 +
 arch/arm64/Makefile          |  9 ++++++++-
 arch/arm64/include/asm/fpu.h | 15 +++++++++++++++
 3 files changed, 24 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm64/include/asm/fpu.h

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 7b11c98b3e84..67f0d3b5b7df 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -30,6 +30,7 @@ config ARM64
 	select ARCH_HAS_GCOV_PROFILE_ALL
 	select ARCH_HAS_GIGANTIC_PAGE
 	select ARCH_HAS_KCOV
+	select ARCH_HAS_KERNEL_FPU_SUPPORT if KERNEL_MODE_NEON
 	select ARCH_HAS_KEEPINITRD
 	select ARCH_HAS_MEMBARRIER_SYNC_CORE
 	select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index 0e075d3c546b..3e863e5b0169 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -36,7 +36,14 @@ ifeq ($(CONFIG_BROKEN_GAS_INST),y)
 $(warning Detected assembler with broken .inst; disassembly will be unreliable)
 endif
 
-KBUILD_CFLAGS	+= -mgeneral-regs-only	\
+# The GCC option -ffreestanding is required in order to compile code containing
+# ARM/NEON intrinsics in a non C99-compliant environment (such as the kernel)
+CC_FLAGS_FPU	:= -ffreestanding
+# Enable <arm_neon.h>
+CC_FLAGS_FPU	+= -isystem $(shell $(CC) -print-file-name=include)
+CC_FLAGS_NO_FPU	:= -mgeneral-regs-only
+
+KBUILD_CFLAGS	+= $(CC_FLAGS_NO_FPU) \
 		   $(compat_vdso) $(cc_has_k_constraint)
 KBUILD_CFLAGS	+= $(call cc-disable-warning, psabi)
 KBUILD_AFLAGS	+= $(compat_vdso)
diff --git a/arch/arm64/include/asm/fpu.h b/arch/arm64/include/asm/fpu.h
new file mode 100644
index 000000000000..2ae50bdce59b
--- /dev/null
+++ b/arch/arm64/include/asm/fpu.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2023 SiFive
+ */
+
+#ifndef __ASM_FPU_H
+#define __ASM_FPU_H
+
+#include <asm/neon.h>
+
+#define kernel_fpu_available()	cpu_has_neon()
+#define kernel_fpu_begin()	kernel_neon_begin()
+#define kernel_fpu_end()	kernel_neon_end()
+
+#endif /* ! __ASM_FPU_H */
-- 
2.44.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v4 08/15] powerpc: Implement ARCH_HAS_KERNEL_FPU_SUPPORT
From: Samuel Holland @ 2024-03-29  7:18 UTC (permalink / raw)
  To: Andrew Morton, linux-arm-kernel, x86
  Cc: linux-kernel, linux-arch, linuxppc-dev, linux-riscv,
	Christoph Hellwig, loongarch, amd-gfx, Samuel Holland,
	Michael Ellerman
In-Reply-To: <20240329072441.591471-1-samuel.holland@sifive.com>

PowerPC provides an equivalent to the common kernel-mode FPU API, but in
a different header and using different function names. The PowerPC API
also requires a non-preemptible context. Add a wrapper header, and
export the CFLAGS adjustments.

Acked-by: Michael Ellerman <mpe@ellerman.id.au> (powerpc)
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
---

(no changes since v1)

 arch/powerpc/Kconfig           |  1 +
 arch/powerpc/Makefile          |  5 ++++-
 arch/powerpc/include/asm/fpu.h | 28 ++++++++++++++++++++++++++++
 3 files changed, 33 insertions(+), 1 deletion(-)
 create mode 100644 arch/powerpc/include/asm/fpu.h

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 1c4be3373686..c42a57b6839d 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -137,6 +137,7 @@ config PPC
 	select ARCH_HAS_GCOV_PROFILE_ALL
 	select ARCH_HAS_HUGEPD			if HUGETLB_PAGE
 	select ARCH_HAS_KCOV
+	select ARCH_HAS_KERNEL_FPU_SUPPORT	if PPC_FPU
 	select ARCH_HAS_MEMBARRIER_CALLBACKS
 	select ARCH_HAS_MEMBARRIER_SYNC_CORE
 	select ARCH_HAS_MEMREMAP_COMPAT_ALIGN	if PPC_64S_HASH_MMU
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index 65261cbe5bfd..93d89f055b70 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -153,6 +153,9 @@ CFLAGS-$(CONFIG_PPC32)	+= $(call cc-option, $(MULTIPLEWORD))
 
 CFLAGS-$(CONFIG_PPC32)	+= $(call cc-option,-mno-readonly-in-sdata)
 
+CC_FLAGS_FPU		:= $(call cc-option,-mhard-float)
+CC_FLAGS_NO_FPU		:= $(call cc-option,-msoft-float)
+
 ifdef CONFIG_FUNCTION_TRACER
 ifdef CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY
 KBUILD_CPPFLAGS	+= -DCC_USING_PATCHABLE_FUNCTION_ENTRY
@@ -174,7 +177,7 @@ asinstr := $(call as-instr,lis 9$(comma)foo@high,-DHAVE_AS_ATHIGH=1)
 
 KBUILD_CPPFLAGS	+= -I $(srctree)/arch/powerpc $(asinstr)
 KBUILD_AFLAGS	+= $(AFLAGS-y)
-KBUILD_CFLAGS	+= $(call cc-option,-msoft-float)
+KBUILD_CFLAGS	+= $(CC_FLAGS_NO_FPU)
 KBUILD_CFLAGS	+= $(CFLAGS-y)
 CPP		= $(CC) -E $(KBUILD_CFLAGS)
 
diff --git a/arch/powerpc/include/asm/fpu.h b/arch/powerpc/include/asm/fpu.h
new file mode 100644
index 000000000000..ca584e4bc40f
--- /dev/null
+++ b/arch/powerpc/include/asm/fpu.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2023 SiFive
+ */
+
+#ifndef _ASM_POWERPC_FPU_H
+#define _ASM_POWERPC_FPU_H
+
+#include <linux/preempt.h>
+
+#include <asm/cpu_has_feature.h>
+#include <asm/switch_to.h>
+
+#define kernel_fpu_available()	(!cpu_has_feature(CPU_FTR_FPU_UNAVAILABLE))
+
+static inline void kernel_fpu_begin(void)
+{
+	preempt_disable();
+	enable_kernel_fp();
+}
+
+static inline void kernel_fpu_end(void)
+{
+	disable_kernel_fp();
+	preempt_enable();
+}
+
+#endif /* ! _ASM_POWERPC_FPU_H */
-- 
2.44.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v4 10/15] x86: Implement ARCH_HAS_KERNEL_FPU_SUPPORT
From: Samuel Holland @ 2024-03-29  7:18 UTC (permalink / raw)
  To: Andrew Morton, linux-arm-kernel, x86
  Cc: linux-kernel, linux-arch, linuxppc-dev, linux-riscv,
	Christoph Hellwig, loongarch, amd-gfx, Samuel Holland,
	Borislav Petkov, Dave Hansen, Ingo Molnar, Thomas Gleixner
In-Reply-To: <20240329072441.591471-1-samuel.holland@sifive.com>

x86 already provides kernel_fpu_begin() and kernel_fpu_end(), but in a
different header. Add a wrapper header, and export the CFLAGS
adjustments as found in lib/Makefile.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
---

(no changes since v1)

 arch/x86/Kconfig           |  1 +
 arch/x86/Makefile          | 20 ++++++++++++++++++++
 arch/x86/include/asm/fpu.h | 13 +++++++++++++
 3 files changed, 34 insertions(+)
 create mode 100644 arch/x86/include/asm/fpu.h

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 39886bab943a..7c9d032ee675 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -83,6 +83,7 @@ config X86
 	select ARCH_HAS_FORTIFY_SOURCE
 	select ARCH_HAS_GCOV_PROFILE_ALL
 	select ARCH_HAS_KCOV			if X86_64
+	select ARCH_HAS_KERNEL_FPU_SUPPORT
 	select ARCH_HAS_MEM_ENCRYPT
 	select ARCH_HAS_MEMBARRIER_SYNC_CORE
 	select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index 662d9d4033e6..5a5f5999c505 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -74,6 +74,26 @@ KBUILD_CFLAGS += -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx
 KBUILD_RUSTFLAGS += --target=$(objtree)/scripts/target.json
 KBUILD_RUSTFLAGS += -Ctarget-feature=-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2
 
+#
+# CFLAGS for compiling floating point code inside the kernel.
+#
+CC_FLAGS_FPU := -msse -msse2
+ifdef CONFIG_CC_IS_GCC
+# Stack alignment mismatch, proceed with caution.
+# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3
+# (8B stack alignment).
+# See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53383
+#
+# The "-msse" in the first argument is there so that the
+# -mpreferred-stack-boundary=3 build error:
+#
+#  -mpreferred-stack-boundary=3 is not between 4 and 12
+#
+# can be triggered. Otherwise gcc doesn't complain.
+CC_FLAGS_FPU += -mhard-float
+CC_FLAGS_FPU += $(call cc-option,-msse -mpreferred-stack-boundary=3,-mpreferred-stack-boundary=4)
+endif
+
 ifeq ($(CONFIG_X86_KERNEL_IBT),y)
 #
 # Kernel IBT has S_CET.NOTRACK_EN=0, as such the compilers must not generate
diff --git a/arch/x86/include/asm/fpu.h b/arch/x86/include/asm/fpu.h
new file mode 100644
index 000000000000..b2743fe19339
--- /dev/null
+++ b/arch/x86/include/asm/fpu.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2023 SiFive
+ */
+
+#ifndef _ASM_X86_FPU_H
+#define _ASM_X86_FPU_H
+
+#include <asm/fpu/api.h>
+
+#define kernel_fpu_available()	true
+
+#endif /* ! _ASM_X86_FPU_H */
-- 
2.44.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v4 11/15] riscv: Add support for kernel-mode FPU
From: Samuel Holland @ 2024-03-29  7:18 UTC (permalink / raw)
  To: Andrew Morton, linux-arm-kernel, x86
  Cc: linux-kernel, linux-arch, linuxppc-dev, linux-riscv,
	Christoph Hellwig, loongarch, amd-gfx, Samuel Holland,
	Palmer Dabbelt
In-Reply-To: <20240329072441.591471-1-samuel.holland@sifive.com>

This is motivated by the amdgpu DRM driver, which needs floating-point
code to support recent hardware. That code is not performance-critical,
so only provide a minimal non-preemptible implementation for now.

Support is limited to riscv64 because riscv32 requires runtime (libgcc)
assistance to convert between doubles and 64-bit integers.

Acked-by: Palmer Dabbelt <palmer@rivosinc.com>
Reviewed-by: Palmer Dabbelt <palmer@rivosinc.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
---

(no changes since v3)

Changes in v3:
 - Limit riscv ARCH_HAS_KERNEL_FPU_SUPPORT to 64BIT

Changes in v2:
 - Remove RISC-V architecture-specific preprocessor check

 arch/riscv/Kconfig                  |  1 +
 arch/riscv/Makefile                 |  3 +++
 arch/riscv/include/asm/fpu.h        | 16 ++++++++++++++++
 arch/riscv/kernel/Makefile          |  1 +
 arch/riscv/kernel/kernel_mode_fpu.c | 28 ++++++++++++++++++++++++++++
 5 files changed, 49 insertions(+)
 create mode 100644 arch/riscv/include/asm/fpu.h
 create mode 100644 arch/riscv/kernel/kernel_mode_fpu.c

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index be09c8836d56..3bcd0d250810 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -27,6 +27,7 @@ config RISCV
 	select ARCH_HAS_GCOV_PROFILE_ALL
 	select ARCH_HAS_GIGANTIC_PAGE
 	select ARCH_HAS_KCOV
+	select ARCH_HAS_KERNEL_FPU_SUPPORT if 64BIT && FPU
 	select ARCH_HAS_MEMBARRIER_CALLBACKS
 	select ARCH_HAS_MEMBARRIER_SYNC_CORE
 	select ARCH_HAS_MMIOWB
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
index 252d63942f34..76ff4033c854 100644
--- a/arch/riscv/Makefile
+++ b/arch/riscv/Makefile
@@ -84,6 +84,9 @@ KBUILD_CFLAGS += -march=$(shell echo $(riscv-march-y) | sed -E 's/(rv32ima|rv64i
 
 KBUILD_AFLAGS += -march=$(riscv-march-y)
 
+# For C code built with floating-point support, exclude V but keep F and D.
+CC_FLAGS_FPU  := -march=$(shell echo $(riscv-march-y) | sed -E 's/(rv32ima|rv64ima)([^v_]*)v?/\1\2/')
+
 KBUILD_CFLAGS += -mno-save-restore
 KBUILD_CFLAGS += -DCONFIG_PAGE_OFFSET=$(CONFIG_PAGE_OFFSET)
 
diff --git a/arch/riscv/include/asm/fpu.h b/arch/riscv/include/asm/fpu.h
new file mode 100644
index 000000000000..91c04c244e12
--- /dev/null
+++ b/arch/riscv/include/asm/fpu.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2023 SiFive
+ */
+
+#ifndef _ASM_RISCV_FPU_H
+#define _ASM_RISCV_FPU_H
+
+#include <asm/switch_to.h>
+
+#define kernel_fpu_available()	has_fpu()
+
+void kernel_fpu_begin(void);
+void kernel_fpu_end(void);
+
+#endif /* ! _ASM_RISCV_FPU_H */
diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
index 81d94a8ee10f..5b243d46f4b1 100644
--- a/arch/riscv/kernel/Makefile
+++ b/arch/riscv/kernel/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_RISCV_MISALIGNED)	+= unaligned_access_speed.o
 obj-$(CONFIG_RISCV_PROBE_UNALIGNED_ACCESS)	+= copy-unaligned.o
 
 obj-$(CONFIG_FPU)		+= fpu.o
+obj-$(CONFIG_FPU)		+= kernel_mode_fpu.o
 obj-$(CONFIG_RISCV_ISA_V)	+= vector.o
 obj-$(CONFIG_RISCV_ISA_V)	+= kernel_mode_vector.o
 obj-$(CONFIG_SMP)		+= smpboot.o
diff --git a/arch/riscv/kernel/kernel_mode_fpu.c b/arch/riscv/kernel/kernel_mode_fpu.c
new file mode 100644
index 000000000000..0ac8348876c4
--- /dev/null
+++ b/arch/riscv/kernel/kernel_mode_fpu.c
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 SiFive
+ */
+
+#include <linux/export.h>
+#include <linux/preempt.h>
+
+#include <asm/csr.h>
+#include <asm/fpu.h>
+#include <asm/processor.h>
+#include <asm/switch_to.h>
+
+void kernel_fpu_begin(void)
+{
+	preempt_disable();
+	fstate_save(current, task_pt_regs(current));
+	csr_set(CSR_SSTATUS, SR_FS);
+}
+EXPORT_SYMBOL_GPL(kernel_fpu_begin);
+
+void kernel_fpu_end(void)
+{
+	csr_clear(CSR_SSTATUS, SR_FS);
+	fstate_restore(current, task_pt_regs(current));
+	preempt_enable();
+}
+EXPORT_SYMBOL_GPL(kernel_fpu_end);
-- 
2.44.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v4 09/15] x86/fpu: Fix asm/fpu/types.h include guard
From: Samuel Holland @ 2024-03-29  7:18 UTC (permalink / raw)
  To: Andrew Morton, linux-arm-kernel, x86
  Cc: linux-kernel, linux-arch, linuxppc-dev, linux-riscv,
	Christoph Hellwig, loongarch, amd-gfx, Samuel Holland,
	Borislav Petkov, Dave Hansen, Ingo Molnar, Thomas Gleixner
In-Reply-To: <20240329072441.591471-1-samuel.holland@sifive.com>

The include guard should match the filename, or it will conflict with
the newly-added asm/fpu.h.

Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
---

Changes in v4:
 - New patch for v4

 arch/x86/include/asm/fpu/types.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/fpu/types.h b/arch/x86/include/asm/fpu/types.h
index ace9aa3b78a3..eb17f31b06d2 100644
--- a/arch/x86/include/asm/fpu/types.h
+++ b/arch/x86/include/asm/fpu/types.h
@@ -2,8 +2,8 @@
 /*
  * FPU data structures:
  */
-#ifndef _ASM_X86_FPU_H
-#define _ASM_X86_FPU_H
+#ifndef _ASM_X86_FPU_TYPES_H
+#define _ASM_X86_FPU_TYPES_H
 
 #include <asm/page_types.h>
 
@@ -596,4 +596,4 @@ struct fpu_state_config {
 /* FPU state configuration information */
 extern struct fpu_state_config fpu_kernel_cfg, fpu_user_cfg;
 
-#endif /* _ASM_X86_FPU_H */
+#endif /* _ASM_X86_FPU_TYPES_H */
-- 
2.44.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v4 13/15] drm/amd/display: Use ARCH_HAS_KERNEL_FPU_SUPPORT
From: Samuel Holland @ 2024-03-29  7:18 UTC (permalink / raw)
  To: Andrew Morton, linux-arm-kernel, x86
  Cc: linux-kernel, linux-arch, linuxppc-dev, linux-riscv,
	Christoph Hellwig, loongarch, amd-gfx, Samuel Holland,
	Alex Deucher
In-Reply-To: <20240329072441.591471-1-samuel.holland@sifive.com>

Now that all previously-supported architectures select
ARCH_HAS_KERNEL_FPU_SUPPORT, this code can depend on that symbol instead
of the existing list of architectures. It can also take advantage of the
common kernel-mode FPU API and method of adjusting CFLAGS.

Acked-by: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
---

(no changes since v2)

Changes in v2:
 - Split altivec removal to a separate patch
 - Use linux/fpu.h instead of asm/fpu.h in consumers

 drivers/gpu/drm/amd/display/Kconfig           |  2 +-
 .../gpu/drm/amd/display/amdgpu_dm/dc_fpu.c    | 27 ++------------
 drivers/gpu/drm/amd/display/dc/dml/Makefile   | 36 ++-----------------
 drivers/gpu/drm/amd/display/dc/dml2/Makefile  | 36 ++-----------------
 4 files changed, 7 insertions(+), 94 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig
index 901d1961b739..5fcd4f778dc3 100644
--- a/drivers/gpu/drm/amd/display/Kconfig
+++ b/drivers/gpu/drm/amd/display/Kconfig
@@ -8,7 +8,7 @@ config DRM_AMD_DC
 	depends on BROKEN || !CC_IS_CLANG || ARM64 || RISCV || SPARC64 || X86_64
 	select SND_HDA_COMPONENT if SND_HDA_CORE
 	# !CC_IS_CLANG: https://github.com/ClangBuiltLinux/linux/issues/1752
-	select DRM_AMD_DC_FP if (X86 || LOONGARCH || (PPC64 && ALTIVEC) || (ARM64 && KERNEL_MODE_NEON && !CC_IS_CLANG))
+	select DRM_AMD_DC_FP if ARCH_HAS_KERNEL_FPU_SUPPORT && (!ARM64 || !CC_IS_CLANG)
 	help
 	  Choose this option if you want to use the new display engine
 	  support for AMDGPU. This adds required support for Vega and
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
index 0de16796466b..e46f8ce41d87 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
@@ -26,16 +26,7 @@
 
 #include "dc_trace.h"
 
-#if defined(CONFIG_X86)
-#include <asm/fpu/api.h>
-#elif defined(CONFIG_PPC64)
-#include <asm/switch_to.h>
-#include <asm/cputable.h>
-#elif defined(CONFIG_ARM64)
-#include <asm/neon.h>
-#elif defined(CONFIG_LOONGARCH)
-#include <asm/fpu.h>
-#endif
+#include <linux/fpu.h>
 
 /**
  * DOC: DC FPU manipulation overview
@@ -87,16 +78,9 @@ void dc_fpu_begin(const char *function_name, const int line)
 	WARN_ON_ONCE(!in_task());
 	preempt_disable();
 	depth = __this_cpu_inc_return(fpu_recursion_depth);
-
 	if (depth == 1) {
-#if defined(CONFIG_X86) || defined(CONFIG_LOONGARCH)
+		BUG_ON(!kernel_fpu_available());
 		kernel_fpu_begin();
-#elif defined(CONFIG_PPC64)
-		if (!cpu_has_feature(CPU_FTR_FPU_UNAVAILABLE))
-			enable_kernel_fp();
-#elif defined(CONFIG_ARM64)
-		kernel_neon_begin();
-#endif
 	}
 
 	TRACE_DCN_FPU(true, function_name, line, depth);
@@ -118,14 +102,7 @@ void dc_fpu_end(const char *function_name, const int line)
 
 	depth = __this_cpu_dec_return(fpu_recursion_depth);
 	if (depth == 0) {
-#if defined(CONFIG_X86) || defined(CONFIG_LOONGARCH)
 		kernel_fpu_end();
-#elif defined(CONFIG_PPC64)
-		if (!cpu_has_feature(CPU_FTR_FPU_UNAVAILABLE))
-			disable_kernel_fp();
-#elif defined(CONFIG_ARM64)
-		kernel_neon_end();
-#endif
 	} else {
 		WARN_ON_ONCE(depth < 0);
 	}
diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile
index 59d3972341d2..a94b6d546cd1 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile
@@ -25,40 +25,8 @@
 # It provides the general basic services required by other DAL
 # subcomponents.
 
-ifdef CONFIG_X86
-dml_ccflags-$(CONFIG_CC_IS_GCC) := -mhard-float
-dml_ccflags := $(dml_ccflags-y) -msse
-endif
-
-ifdef CONFIG_PPC64
-dml_ccflags := -mhard-float
-endif
-
-ifdef CONFIG_ARM64
-dml_rcflags := -mgeneral-regs-only
-endif
-
-ifdef CONFIG_LOONGARCH
-dml_ccflags := -mfpu=64
-dml_rcflags := -msoft-float
-endif
-
-ifdef CONFIG_CC_IS_GCC
-ifneq ($(call gcc-min-version, 70100),y)
-IS_OLD_GCC = 1
-endif
-endif
-
-ifdef CONFIG_X86
-ifdef IS_OLD_GCC
-# Stack alignment mismatch, proceed with caution.
-# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3
-# (8B stack alignment).
-dml_ccflags += -mpreferred-stack-boundary=4
-else
-dml_ccflags += -msse2
-endif
-endif
+dml_ccflags := $(CC_FLAGS_FPU)
+dml_rcflags := $(CC_FLAGS_NO_FPU)
 
 ifneq ($(CONFIG_FRAME_WARN),0)
 ifeq ($(filter y,$(CONFIG_KASAN)$(CONFIG_KCSAN)),y)
diff --git a/drivers/gpu/drm/amd/display/dc/dml2/Makefile b/drivers/gpu/drm/amd/display/dc/dml2/Makefile
index 7b51364084b5..4f6c804a26ad 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dml2/Makefile
@@ -24,40 +24,8 @@
 #
 # Makefile for dml2.
 
-ifdef CONFIG_X86
-dml2_ccflags-$(CONFIG_CC_IS_GCC) := -mhard-float
-dml2_ccflags := $(dml2_ccflags-y) -msse
-endif
-
-ifdef CONFIG_PPC64
-dml2_ccflags := -mhard-float
-endif
-
-ifdef CONFIG_ARM64
-dml2_rcflags := -mgeneral-regs-only
-endif
-
-ifdef CONFIG_LOONGARCH
-dml2_ccflags := -mfpu=64
-dml2_rcflags := -msoft-float
-endif
-
-ifdef CONFIG_CC_IS_GCC
-ifeq ($(call cc-ifversion, -lt, 0701, y), y)
-IS_OLD_GCC = 1
-endif
-endif
-
-ifdef CONFIG_X86
-ifdef IS_OLD_GCC
-# Stack alignment mismatch, proceed with caution.
-# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3
-# (8B stack alignment).
-dml2_ccflags += -mpreferred-stack-boundary=4
-else
-dml2_ccflags += -msse2
-endif
-endif
+dml2_ccflags := $(CC_FLAGS_FPU)
+dml2_rcflags := $(CC_FLAGS_NO_FPU)
 
 ifneq ($(CONFIG_FRAME_WARN),0)
 ifeq ($(filter y,$(CONFIG_KASAN)$(CONFIG_KCSAN)),y)
-- 
2.44.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v4 12/15] drm/amd/display: Only use hard-float, not altivec on powerpc
From: Samuel Holland @ 2024-03-29  7:18 UTC (permalink / raw)
  To: Andrew Morton, linux-arm-kernel, x86
  Cc: linux-kernel, linux-arch, linuxppc-dev, linux-riscv,
	Christoph Hellwig, loongarch, amd-gfx, Michael Ellerman,
	Alex Deucher, Samuel Holland
In-Reply-To: <20240329072441.591471-1-samuel.holland@sifive.com>

From: Michael Ellerman <mpe@ellerman.id.au>

The compiler flags enable altivec, but that is not required; hard-float
is sufficient for the code to build and function.

Drop altivec from the compiler flags and adjust the enable/disable code
to only enable FPU use.

Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
---

(no changes since v2)

Changes in v2:
 - New patch for v2

 drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c | 12 ++----------
 drivers/gpu/drm/amd/display/dc/dml/Makefile    |  2 +-
 drivers/gpu/drm/amd/display/dc/dml2/Makefile   |  2 +-
 3 files changed, 4 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
index 4ae4720535a5..0de16796466b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
@@ -92,11 +92,7 @@ void dc_fpu_begin(const char *function_name, const int line)
 #if defined(CONFIG_X86) || defined(CONFIG_LOONGARCH)
 		kernel_fpu_begin();
 #elif defined(CONFIG_PPC64)
-		if (cpu_has_feature(CPU_FTR_VSX_COMP))
-			enable_kernel_vsx();
-		else if (cpu_has_feature(CPU_FTR_ALTIVEC_COMP))
-			enable_kernel_altivec();
-		else if (!cpu_has_feature(CPU_FTR_FPU_UNAVAILABLE))
+		if (!cpu_has_feature(CPU_FTR_FPU_UNAVAILABLE))
 			enable_kernel_fp();
 #elif defined(CONFIG_ARM64)
 		kernel_neon_begin();
@@ -125,11 +121,7 @@ void dc_fpu_end(const char *function_name, const int line)
 #if defined(CONFIG_X86) || defined(CONFIG_LOONGARCH)
 		kernel_fpu_end();
 #elif defined(CONFIG_PPC64)
-		if (cpu_has_feature(CPU_FTR_VSX_COMP))
-			disable_kernel_vsx();
-		else if (cpu_has_feature(CPU_FTR_ALTIVEC_COMP))
-			disable_kernel_altivec();
-		else if (!cpu_has_feature(CPU_FTR_FPU_UNAVAILABLE))
+		if (!cpu_has_feature(CPU_FTR_FPU_UNAVAILABLE))
 			disable_kernel_fp();
 #elif defined(CONFIG_ARM64)
 		kernel_neon_end();
diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile
index c4a5efd2dda5..59d3972341d2 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile
@@ -31,7 +31,7 @@ dml_ccflags := $(dml_ccflags-y) -msse
 endif
 
 ifdef CONFIG_PPC64
-dml_ccflags := -mhard-float -maltivec
+dml_ccflags := -mhard-float
 endif
 
 ifdef CONFIG_ARM64
diff --git a/drivers/gpu/drm/amd/display/dc/dml2/Makefile b/drivers/gpu/drm/amd/display/dc/dml2/Makefile
index acff3449b8d7..7b51364084b5 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dml2/Makefile
@@ -30,7 +30,7 @@ dml2_ccflags := $(dml2_ccflags-y) -msse
 endif
 
 ifdef CONFIG_PPC64
-dml2_ccflags := -mhard-float -maltivec
+dml2_ccflags := -mhard-float
 endif
 
 ifdef CONFIG_ARM64
-- 
2.44.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v4 15/15] selftests/fpu: Allow building on other architectures
From: Samuel Holland @ 2024-03-29  7:18 UTC (permalink / raw)
  To: Andrew Morton, linux-arm-kernel, x86
  Cc: linux-kernel, linux-arch, linuxppc-dev, linux-riscv,
	Christoph Hellwig, loongarch, amd-gfx, Samuel Holland
In-Reply-To: <20240329072441.591471-1-samuel.holland@sifive.com>

Now that ARCH_HAS_KERNEL_FPU_SUPPORT provides a common way to compile
and run floating-point code, this test is no longer x86-specific.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
---

(no changes since v1)

 lib/Kconfig.debug   |  2 +-
 lib/Makefile        | 25 ++-----------------------
 lib/test_fpu_glue.c |  5 ++++-
 3 files changed, 7 insertions(+), 25 deletions(-)

diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index c63a5fbf1f1c..f93e778e0405 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2890,7 +2890,7 @@ config TEST_FREE_PAGES
 
 config TEST_FPU
 	tristate "Test floating point operations in kernel space"
-	depends on X86 && !KCOV_INSTRUMENT_ALL
+	depends on ARCH_HAS_KERNEL_FPU_SUPPORT && !KCOV_INSTRUMENT_ALL
 	help
 	  Enable this option to add /sys/kernel/debug/selftest_helpers/test_fpu
 	  which will trigger a sequence of floating point operations. This is used
diff --git a/lib/Makefile b/lib/Makefile
index fcb35bf50979..e44ad11f77b5 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -110,31 +110,10 @@ CFLAGS_test_fprobe.o += $(CC_FLAGS_FTRACE)
 obj-$(CONFIG_FPROBE_SANITY_TEST) += test_fprobe.o
 obj-$(CONFIG_TEST_OBJPOOL) += test_objpool.o
 
-#
-# CFLAGS for compiling floating point code inside the kernel. x86/Makefile turns
-# off the generation of FPU/SSE* instructions for kernel proper but FPU_FLAGS
-# get appended last to CFLAGS and thus override those previous compiler options.
-#
-FPU_CFLAGS := -msse -msse2
-ifdef CONFIG_CC_IS_GCC
-# Stack alignment mismatch, proceed with caution.
-# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3
-# (8B stack alignment).
-# See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53383
-#
-# The "-msse" in the first argument is there so that the
-# -mpreferred-stack-boundary=3 build error:
-#
-#  -mpreferred-stack-boundary=3 is not between 4 and 12
-#
-# can be triggered. Otherwise gcc doesn't complain.
-FPU_CFLAGS += -mhard-float
-FPU_CFLAGS += $(call cc-option,-msse -mpreferred-stack-boundary=3,-mpreferred-stack-boundary=4)
-endif
-
 obj-$(CONFIG_TEST_FPU) += test_fpu.o
 test_fpu-y := test_fpu_glue.o test_fpu_impl.o
-CFLAGS_test_fpu_impl.o += $(FPU_CFLAGS)
+CFLAGS_test_fpu_impl.o += $(CC_FLAGS_FPU)
+CFLAGS_REMOVE_test_fpu_impl.o += $(CC_FLAGS_NO_FPU)
 
 # Some KUnit files (hooks.o) need to be built-in even when KUnit is a module,
 # so we can't just use obj-$(CONFIG_KUNIT).
diff --git a/lib/test_fpu_glue.c b/lib/test_fpu_glue.c
index 85963d7be826..eef282a2715f 100644
--- a/lib/test_fpu_glue.c
+++ b/lib/test_fpu_glue.c
@@ -17,7 +17,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/debugfs.h>
-#include <asm/fpu/api.h>
+#include <linux/fpu.h>
 
 #include "test_fpu.h"
 
@@ -38,6 +38,9 @@ static struct dentry *selftest_dir;
 
 static int __init test_fpu_init(void)
 {
+	if (!kernel_fpu_available())
+		return -EINVAL;
+
 	selftest_dir = debugfs_create_dir("selftest_helpers", NULL);
 	if (!selftest_dir)
 		return -ENOMEM;
-- 
2.44.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [RFC 0/3] Add i.MX8Q HSIO PHY driver support
From: Richard Zhu @ 2024-03-29  7:31 UTC (permalink / raw)
  To: vkoul, kishon, robh+dt, krzysztof.kozlowski+dt, conor+dt,
	frank.li
  Cc: hongxing.zhu, linux-phy, devicetree, linux-arm-kernel,
	linux-kernel, kernel, linux-imx

i.MX8Q HSIO module has PHY and mix control regions.
This patch-set adds i.MX8Q HSIO PHY driver support, and provides
standard PHY phandles that can be used by i.MX8Q PCIe or
SATA driver later.

[RFC 1/3] dt-bindings: phy: Add i.MX8Q HSIO SerDes PHY binding
[RFC 2/3] dt-bindings: phy: phy-imx8-pcie: Add binding for i.MX8Q
[RFC 3/3] phy: freescale: imx8q-hsio: Add i.MX8Q HSIO PHY driver

Documentation/devicetree/bindings/phy/fsl,imx8q-hsio.yaml | 143 ++++++++++++++++++++++++
drivers/phy/freescale/Kconfig                             |   8 ++
drivers/phy/freescale/Makefile                            |   1 +
drivers/phy/freescale/phy-fsl-imx8q-hsio.c                | 518 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
include/dt-bindings/phy/phy-imx8-pcie.h                   |  26 +++++
5 files changed, 696 insertions(+)


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [RFC 1/3] dt-bindings: phy: Add i.MX8Q HSIO SerDes PHY binding
From: Richard Zhu @ 2024-03-29  7:31 UTC (permalink / raw)
  To: vkoul, kishon, robh+dt, krzysztof.kozlowski+dt, conor+dt,
	frank.li
  Cc: hongxing.zhu, linux-phy, devicetree, linux-arm-kernel,
	linux-kernel, kernel, linux-imx
In-Reply-To: <1711697493-16151-1-git-send-email-hongxing.zhu@nxp.com>

Add i.MX8QM and i.MX8QXP HSIO SerDes PHY binding.
- Use the controller ID to specify which controller is binded to the
PHY.
- Introduce one HSIO configuration, mandatory required to set
"PCIE_AB_SELECT" and "PHY_X1_EPCS_SEL" during the initialization.

Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
---
 .../bindings/phy/fsl,imx8q-hsio.yaml          | 143 ++++++++++++++++++
 1 file changed, 143 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/fsl,imx8q-hsio.yaml

diff --git a/Documentation/devicetree/bindings/phy/fsl,imx8q-hsio.yaml b/Documentation/devicetree/bindings/phy/fsl,imx8q-hsio.yaml
new file mode 100644
index 000000000000..506551d4d94a
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/fsl,imx8q-hsio.yaml
@@ -0,0 +1,143 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/fsl,imx8q-hsio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Freescale i.MX8Q SoC series HSIO SERDES PHY
+
+maintainers:
+  - Richard Zhu <hongxing.zhu@nxp.com>
+
+properties:
+  compatible:
+    enum:
+      - fsl,imx8qxp-serdes
+      - fsl,imx8qm-serdes
+  reg:
+    minItems: 4
+    maxItems: 4
+
+  "#phy-cells":
+    const: 3
+    description: |
+      The first number defines the ID of the PHY contained in the HSIO macro.
+      The second defines controller ID binded to the PHY. The third defines the
+      HSIO configuratons refer to the different use cases. They are defined in
+      dt-bindings/phy/phy-imx8-pcie.h
+
+  reg-names:
+    items:
+      - const: reg
+      - const: phy
+      - const: ctrl
+      - const: misc
+
+  clocks:
+    minItems: 5
+    maxItems: 14
+
+  clock-names:
+    minItems: 5
+    maxItems: 14
+
+  fsl,refclk-pad-mode:
+    description: |
+      Specifies the mode of the refclk pad used. It can be UNUSED(PHY
+      refclock is derived from SoC internal source), INPUT(PHY refclock
+      is provided externally via the refclk pad) or OUTPUT(PHY refclock
+      is derived from SoC internal source and provided on the refclk pad).
+      Refer include/dt-bindings/phy/phy-imx8-pcie.h for the constants
+      to be used.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [ 0, 1, 2 ]
+
+  power-domains:
+    description: |
+      i.MX8Q HSIO SerDes power domains. i.MX8QXP has one SerDes power domains.
+      And i.MX8QM has two.
+    minItems: 1
+    maxItems: 2
+
+required:
+  - compatible
+  - reg
+  - "#phy-cells"
+  - clocks
+  - clock-names
+  - fsl,refclk-pad-mode
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - fsl,imx8qxp-serdes
+    then:
+      properties:
+        clock-names:
+          items:
+            - const: apb_pclk0
+            - const: pclk0
+            - const: phy0_crr
+            - const: ctl0_crr
+            - const: misc_crr
+        power-domains:
+          minItems: 1
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - fsl,imx8qm-serdes
+    then:
+      properties:
+        clock-names:
+          items:
+            - const: pclk0
+            - const: pclk1
+            - const: apb_pclk0
+            - const: apb_pclk1
+            - const: pclk2
+            - const: epcs_tx
+            - const: epcs_rx
+            - const: apb_pclk2
+            - const: phy0_crr
+            - const: phy1_crr
+            - const: ctl0_crr
+            - const: ctl1_crr
+            - const: ctl2_crr
+            - const: misc_crr
+        power-domains:
+          minItems: 2
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/imx8-clock.h>
+    #include <dt-bindings/clock/imx8-lpcg.h>
+    #include <dt-bindings/firmware/imx/rsrc.h>
+    #include <dt-bindings/phy/phy-imx8-pcie.h>
+
+    serdes: phy@5f1a0000 {
+            compatible = "fsl,imx8qxp-serdes";
+            reg = <0x5f1a0000 0x10000>,
+                  <0x5f120000 0x10000>,
+                  <0x5f140000 0x10000>,
+                  <0x5f160000 0x10000>;
+            reg-names = "reg", "phy", "ctrl", "misc";
+            clocks = <&phyx1_lpcg IMX_LPCG_CLK_0>,
+                     <&phyx1_lpcg IMX_LPCG_CLK_4>,
+                     <&phyx1_crr1_lpcg IMX_LPCG_CLK_4>,
+                     <&pcieb_crr3_lpcg IMX_LPCG_CLK_4>,
+                     <&misc_crr5_lpcg IMX_LPCG_CLK_4>;
+            clock-names = "apb_pclk0", "pclk0", "phy0_crr", "ctl0_crr",
+                          "misc_crr";
+            power-domains = <&pd IMX_SC_R_SERDES_1>;
+            #phy-cells = <3>;
+            status = "disabled";
+    };
+...
-- 
2.37.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [RFC 2/3] dt-bindings: phy: phy-imx8-pcie: Add binding for i.MX8Q HSIO SerDes PHY
From: Richard Zhu @ 2024-03-29  7:31 UTC (permalink / raw)
  To: vkoul, kishon, robh+dt, krzysztof.kozlowski+dt, conor+dt,
	frank.li
  Cc: hongxing.zhu, linux-phy, devicetree, linux-arm-kernel,
	linux-kernel, kernel, linux-imx
In-Reply-To: <1711697493-16151-1-git-send-email-hongxing.zhu@nxp.com>

Add binding for controller ID and HSIO configuration setting of the
i.MX8Q HSIO SerDes PHY.

Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
---
 include/dt-bindings/phy/phy-imx8-pcie.h | 26 +++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/include/dt-bindings/phy/phy-imx8-pcie.h b/include/dt-bindings/phy/phy-imx8-pcie.h
index 8bbe2d6538d8..5cd5580879fa 100644
--- a/include/dt-bindings/phy/phy-imx8-pcie.h
+++ b/include/dt-bindings/phy/phy-imx8-pcie.h
@@ -11,4 +11,30 @@
 #define IMX8_PCIE_REFCLK_PAD_INPUT	1
 #define IMX8_PCIE_REFCLK_PAD_OUTPUT	2
 
+/*
+ * i.MX8QM HSIO subsystem has three lane PHYs and three controllers:
+ * PCIEA(2 lanes capapble PCIe controller), PCIEB (only support one
+ * lane) and SATA.
+ * In the different use cases. PCIEA can be binded to PHY lane0, lane1
+ * or Lane0 and lane1. PCIEB can be binded to lane1 or lane2 PHY. SATA
+ * can only be binded to last lane2 PHY.
+ * Define i.MX8Q HSIO controller ID here to specify the controller
+ * binded to the PHY.
+ * Meanwhile, i.MX8QXP HSIO subsystem has one lane PHY and PCIEB(only
+ * support one lane) controller.
+ */
+#define IMX8Q_HSIO_PCIEA_ID	0
+#define IMX8Q_HSIO_PCIEB_ID	1
+#define IMX8Q_HSIO_SATA_ID	2
+
+/*
+ * On i.MX8QM, PCIEA is mandatory required if the HSIO is enabled.
+ * Define configurations beside PCIEA is enabled.
+ * On i.MX8QXP, HSIO module only has PCIEB and one lane PHY.
+ * The "IMX8Q_HSIO_CFG_PCIEB" can be used on i.MX8QXP platforms.
+ */
+#define IMX8Q_HSIO_CFG_SATA		1
+#define IMX8Q_HSIO_CFG_PCIEB		2
+#define IMX8Q_HSIO_CFG_PCIEBSATA	3
+
 #endif /* _DT_BINDINGS_IMX8_PCIE_H */
-- 
2.37.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [RFC 3/3] phy: freescale: imx8q-hsio: Add i.MX8Q HSIO PHY driver support
From: Richard Zhu @ 2024-03-29  7:31 UTC (permalink / raw)
  To: vkoul, kishon, robh+dt, krzysztof.kozlowski+dt, conor+dt,
	frank.li
  Cc: hongxing.zhu, linux-phy, devicetree, linux-arm-kernel,
	linux-kernel, kernel, linux-imx
In-Reply-To: <1711697493-16151-1-git-send-email-hongxing.zhu@nxp.com>

Add i.MX8Q HSIO PHY driver support.
- Add one HSIO configuration property, that used to select the
"PCIE_AB_SELECT" and "PHY_X1_EPCS_SEL" during the initialization.

Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
---
 drivers/phy/freescale/Kconfig              |   8 +
 drivers/phy/freescale/Makefile             |   1 +
 drivers/phy/freescale/phy-fsl-imx8q-hsio.c | 518 +++++++++++++++++++++
 3 files changed, 527 insertions(+)
 create mode 100644 drivers/phy/freescale/phy-fsl-imx8q-hsio.c

diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig
index 853958fb2c06..bcddddef1cbb 100644
--- a/drivers/phy/freescale/Kconfig
+++ b/drivers/phy/freescale/Kconfig
@@ -35,6 +35,14 @@ config PHY_FSL_IMX8M_PCIE
 	  Enable this to add support for the PCIE PHY as found on
 	  i.MX8M family of SOCs.
 
+config PHY_FSL_IMX8Q_HSIO
+	tristate "Freescale i.MX8Q HSIO PHY"
+	depends on OF && HAS_IOMEM
+	select GENERIC_PHY
+	help
+	  Enable this to add support for the HSIO PHY as found on
+	  i.MX8Q family of SOCs.
+
 endif
 
 config PHY_FSL_LYNX_28G
diff --git a/drivers/phy/freescale/Makefile b/drivers/phy/freescale/Makefile
index cedb328bc4d2..db888c37fcf9 100644
--- a/drivers/phy/freescale/Makefile
+++ b/drivers/phy/freescale/Makefile
@@ -3,4 +3,5 @@ obj-$(CONFIG_PHY_FSL_IMX8MQ_USB)	+= phy-fsl-imx8mq-usb.o
 obj-$(CONFIG_PHY_MIXEL_LVDS_PHY)	+= phy-fsl-imx8qm-lvds-phy.o
 obj-$(CONFIG_PHY_MIXEL_MIPI_DPHY)	+= phy-fsl-imx8-mipi-dphy.o
 obj-$(CONFIG_PHY_FSL_IMX8M_PCIE)	+= phy-fsl-imx8m-pcie.o
+obj-$(CONFIG_PHY_FSL_IMX8Q_HSIO)	+= phy-fsl-imx8q-hsio.o
 obj-$(CONFIG_PHY_FSL_LYNX_28G)		+= phy-fsl-lynx-28g.o
diff --git a/drivers/phy/freescale/phy-fsl-imx8q-hsio.c b/drivers/phy/freescale/phy-fsl-imx8q-hsio.c
new file mode 100644
index 000000000000..8deede5e8e8e
--- /dev/null
+++ b/drivers/phy/freescale/phy-fsl-imx8q-hsio.c
@@ -0,0 +1,518 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2024 NXP
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/pci_regs.h>
+#include <linux/phy/phy.h>
+#include <linux/phy/pcie.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/phy/phy-imx8-pcie.h>
+
+#define MAX_NUM_LANES	3
+#define LANE_NUM_CLKS	5
+
+/* Parameters for the waiting for PCIe PHY PLL to lock */
+#define PHY_INIT_WAIT_USLEEP_MAX	10
+#define PHY_INIT_WAIT_TIMEOUT		(1000 * PHY_INIT_WAIT_USLEEP_MAX)
+
+/* i.MX8Q HSIO registers */
+#define CTRL0			0x0
+#define APB_RSTN_0		BIT(0)
+#define APB_RSTN_1		BIT(1)
+#define PIPE_RSTN_0_MASK	GENMASK(25, 24)
+#define PIPE_RSTN_1_MASK	GENMASK(27, 26)
+#define MODE_MASK		GENMASK(20, 17)
+#define MODE_PCIE		0x0
+#define MODE_SATA		0x4
+#define DEVICE_TYPE_MASK	GENMASK(27, 24)
+#define EPCS_TXDEEMP		BIT(5)
+#define EPCS_TXDEEMP_SEL	BIT(6)
+#define EPCS_PHYRESET_N		BIT(7)
+#define RESET_N			BIT(12)
+
+#define IOB_RXENA		BIT(0)
+#define IOB_TXENA		BIT(1)
+#define IOB_A_0_TXOE		BIT(2)
+#define IOB_A_0_M1M0_2		BIT(4)
+#define IOB_A_0_M1M0_MASK	GENMASK(4, 3)
+#define PHYX1_EPCS_SEL		BIT(12)
+#define PCIE_AB_SELECT		BIT(13)
+#define CLKREQN_OUT_OVERRIDE	GENMASK(25, 24)
+
+#define PHY_STTS0		0x4
+#define LANE0_TX_PLL_LOCK	BIT(4)
+#define LANE1_TX_PLL_LOCK	BIT(12)
+
+#define CTRL2			0x8
+#define LTSSM_ENABLE		BIT(4)
+#define BUTTON_RST_N		BIT(21)
+#define PERST_N			BIT(22)
+#define POWER_UP_RST_N		BIT(23)
+
+#define PCIE_STTS0		0xc
+#define PM_REQ_CORE_RST		BIT(19)
+
+#define REG48_PMA_STATUS	0x30
+#define REG48_PMA_RDY		BIT(7)
+
+struct imx8q_hsio_drvdata {
+	int num_lane;
+};
+
+struct imx8q_hsio_lane {
+	const char * const *clk_names;
+	struct clk_bulk_data clks[LANE_NUM_CLKS];
+	u32 clks_cnt;
+	u32 ctrl_id;
+	u32 ctrl_off;
+	u32 idx;
+	u32 phy_off;
+	struct imx8q_hsio_priv *priv;
+	struct phy *phy;
+	enum phy_mode lane_mode;
+};
+
+struct imx8q_hsio_priv {
+	void __iomem *base;
+	struct device *dev;
+	u32 refclk_pad_mode;
+	u32 hsio_cfg;
+	struct regmap *phy;
+	struct regmap *ctrl;
+	struct regmap *misc;
+	const struct imx8q_hsio_drvdata *drvdata;
+	struct imx8q_hsio_lane lane[MAX_NUM_LANES];
+};
+
+static const char * const imx8q_hsio_lan0_pcie_clks[] = {"apb_pclk0", "pclk0",
+	"ctl0_crr", "phy0_crr", "misc_crr"};
+static const char * const imx8q_hsio_lan1_pciea_clks[] = {"apb_pclk1", "pclk1",
+	"ctl0_crr", "phy0_crr", "misc_crr"};
+static const char * const imx8q_hsio_lan1_pcieb_clks[] = {"apb_pclk1", "pclk1",
+	"ctl1_crr", "phy0_crr", "misc_crr"};
+static const char * const imx8q_hsio_lan2_pcieb_clks[] = {"apb_pclk2", "pclk2",
+	"ctl1_crr", "phy1_crr", "misc_crr"};
+static const char * const imx8q_hsio_lane_sata_clks[] = {"pclk2", "epcs_tx",
+	"epcs_rx", "phy1_crr", "misc_crr"};
+
+static const struct regmap_config regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+};
+
+static int imx8q_hsio_init(struct phy *phy)
+{
+	int ret, i;
+	struct imx8q_hsio_lane *lane = phy_get_drvdata(phy);
+	struct imx8q_hsio_priv *priv = lane->priv;
+	struct device *dev = priv->dev;
+
+	/* Assign clocks refer to different modes */
+	switch (lane->ctrl_id) {
+	case IMX8Q_HSIO_PCIEA_ID:
+		if (lane->idx > 1) {
+			dev_err(dev, "invalid lane ID.");
+			return -EINVAL;
+		}
+
+		lane->lane_mode = PHY_MODE_PCIE;
+		lane->ctrl_off = 0;
+		lane->phy_off = 0;
+
+		for (i = 0; i < LANE_NUM_CLKS; i++) {
+			if (lane->idx)
+				lane->clks[i].id = imx8q_hsio_lan1_pciea_clks[i];
+			else
+				lane->clks[i].id = imx8q_hsio_lan0_pcie_clks[i];
+		}
+		break;
+	case IMX8Q_HSIO_PCIEB_ID:
+		if (lane->idx > 2) {
+			dev_err(dev, "invalid lane ID.");
+			return -EINVAL;
+		}
+
+		lane->lane_mode = PHY_MODE_PCIE;
+		if (lane->idx == 0) {
+			/* i.MX8QXP */
+			lane->ctrl_off = 0;
+			lane->phy_off = 0;
+		} else {
+			/*
+			 * On i.MX8QM, only second or third lane PHY can
+			 * be binded to PCIEB.
+			 */
+			lane->ctrl_off = SZ_64K;
+			if (lane->idx == 1)
+				lane->phy_off = 0;
+			else /* idx == 2, the third lane is binded to PCIEB */
+				lane->phy_off = SZ_64K;
+		}
+
+		for (i = 0; i < LANE_NUM_CLKS; i++) {
+			if (lane->idx == 1)
+				lane->clks[i].id = imx8q_hsio_lan1_pcieb_clks[i];
+			else if (lane->idx == 2)
+				lane->clks[i].id = imx8q_hsio_lan2_pcieb_clks[i];
+			else /* i.MX8QXP only has PCIEB, it's idx == 0 */
+				lane->clks[i].id = imx8q_hsio_lan0_pcie_clks[i];
+
+		}
+		break;
+	case IMX8Q_HSIO_SATA_ID:
+		/* On i.MX8QM, only the third lane PHY can be binded to SATA */
+		if (lane->idx != 2) {
+			dev_err(dev, "invalid lane ID.");
+			return -EINVAL;
+		}
+		lane->ctrl_off = SZ_128K;
+		lane->lane_mode = PHY_MODE_SATA;
+		lane->phy_off = SZ_64K;
+
+		for (i = 0; i < LANE_NUM_CLKS; i++)
+			lane->clks[i].id = imx8q_hsio_lane_sata_clks[i];
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Fetch clocks */
+	ret = devm_clk_bulk_get(dev, LANE_NUM_CLKS, lane->clks);
+	if (ret)
+		return ret;
+
+	ret = clk_bulk_prepare_enable(LANE_NUM_CLKS, lane->clks);
+	if (ret)
+		return ret;
+
+	/* allow the clocks to stabilize */
+	usleep_range(200, 500);
+	return 0;
+}
+
+static int imx8q_hsio_exit(struct phy *phy)
+{
+	struct imx8q_hsio_lane *lane = phy_get_drvdata(phy);
+
+	clk_bulk_disable_unprepare(LANE_NUM_CLKS, lane->clks);
+
+	return 0;
+}
+
+static void imx8q_hsio_pcie_phy_resets(struct phy *phy)
+{
+	struct imx8q_hsio_lane *lane = phy_get_drvdata(phy);
+	struct imx8q_hsio_priv *priv = lane->priv;
+
+	regmap_clear_bits(priv->ctrl, lane->ctrl_off + CTRL2, BUTTON_RST_N);
+	regmap_clear_bits(priv->ctrl, lane->ctrl_off + CTRL2, PERST_N);
+	regmap_clear_bits(priv->ctrl, lane->ctrl_off + CTRL2, POWER_UP_RST_N);
+	regmap_set_bits(priv->ctrl, lane->ctrl_off + CTRL2, BUTTON_RST_N);
+	regmap_set_bits(priv->ctrl, lane->ctrl_off + CTRL2, PERST_N);
+	regmap_set_bits(priv->ctrl, lane->ctrl_off + CTRL2, POWER_UP_RST_N);
+
+	if (lane->idx == 1) {
+		/* The second lane */
+		regmap_set_bits(priv->phy, lane->phy_off + CTRL0, APB_RSTN_1);
+		regmap_set_bits(priv->phy, lane->phy_off + CTRL0, PIPE_RSTN_1_MASK);
+	} else {
+		regmap_set_bits(priv->phy, lane->phy_off + CTRL0, APB_RSTN_0);
+		regmap_set_bits(priv->phy, lane->phy_off + CTRL0, PIPE_RSTN_0_MASK);
+	}
+}
+
+static void imx8q_hsio_sata_phy_resets(struct phy *phy)
+{
+	struct imx8q_hsio_lane *lane = phy_get_drvdata(phy);
+	struct imx8q_hsio_priv *priv = lane->priv;
+
+	/* clear PHY RST, then set it */
+	regmap_clear_bits(priv->ctrl, lane->ctrl_off + CTRL0, EPCS_PHYRESET_N);
+
+	regmap_set_bits(priv->ctrl, lane->ctrl_off + CTRL0, EPCS_PHYRESET_N);
+
+	/* CTRL RST: SET -> delay 1 us -> CLEAR -> SET */
+	regmap_set_bits(priv->ctrl, lane->ctrl_off + CTRL0, RESET_N);
+	udelay(1);
+	regmap_clear_bits(priv->ctrl, lane->ctrl_off + CTRL0, RESET_N);
+	regmap_set_bits(priv->ctrl, lane->ctrl_off + CTRL0, RESET_N);
+}
+
+static void imx8q_hsio_configure_clk_pad(struct phy *phy)
+{
+	bool pll = false;
+	u32 pad_mode;
+	struct imx8q_hsio_lane *lane = phy_get_drvdata(phy);
+	struct imx8q_hsio_priv *priv = lane->priv;
+
+	pad_mode = priv->refclk_pad_mode;
+	if (pad_mode == IMX8_PCIE_REFCLK_PAD_OUTPUT) {
+		pll = true;
+		regmap_update_bits(priv->misc, CTRL0,
+				   IOB_A_0_TXOE | IOB_A_0_M1M0_MASK,
+				   IOB_A_0_TXOE | IOB_A_0_M1M0_2);
+	}
+
+	regmap_update_bits(priv->misc, CTRL0, IOB_RXENA, pll ? 0 : IOB_RXENA);
+	regmap_update_bits(priv->misc, CTRL0, IOB_TXENA, pll ? IOB_TXENA : 0);
+}
+
+static int imx8q_hsio_power_on(struct phy *phy)
+{
+	int ret;
+	u32 val, cond;
+	struct imx8q_hsio_lane *lane = phy_get_drvdata(phy);
+	struct imx8q_hsio_priv *priv = lane->priv;
+
+	if (lane->lane_mode == PHY_MODE_PCIE)
+		imx8q_hsio_pcie_phy_resets(phy);
+	else
+		/* SATA */
+		regmap_set_bits(priv->phy, lane->phy_off + CTRL0, APB_RSTN_0);
+
+	if (priv->hsio_cfg & IMX8Q_HSIO_CFG_PCIEB)
+		regmap_set_bits(priv->misc, CTRL0, PCIE_AB_SELECT);
+	if (priv->hsio_cfg & IMX8Q_HSIO_CFG_SATA)
+		regmap_set_bits(priv->misc, CTRL0, PHYX1_EPCS_SEL);
+
+	imx8q_hsio_configure_clk_pad(phy);
+
+	if (lane->lane_mode == PHY_MODE_SATA) {
+		/*
+		 * It is possible, for PCIe and SATA are sharing
+		 * the same clock source, HPLL or external oscillator.
+		 * When PCIe is in low power modes (L1.X or L2 etc),
+		 * the clock source can be turned off. In this case,
+		 * if this clock source is required to be toggling by
+		 * SATA, then SATA functions will be abnormal.
+		 * Set the override here to avoid it.
+		 */
+		regmap_set_bits(priv->misc, CTRL0, CLKREQN_OUT_OVERRIDE);
+		regmap_set_bits(priv->ctrl, lane->ctrl_off + CTRL0, EPCS_TXDEEMP);
+		regmap_set_bits(priv->ctrl, lane->ctrl_off + CTRL0, EPCS_TXDEEMP_SEL);
+
+		imx8q_hsio_sata_phy_resets(phy);
+	} else {
+		/* Toggle apb_pclk to make sure clear the PM_REQ_CORE_RST bit */
+		clk_disable_unprepare(lane->clks[0].clk);
+		mdelay(1);
+		ret = clk_prepare_enable(lane->clks[0].clk);
+		if (ret) {
+			dev_err(priv->dev, "unable to enable phy apb_pclk\n");
+			return ret;
+		}
+
+		/* Bit19 PM_REQ_CORE_RST of pcie_stts0 should be cleared. */
+		ret = regmap_read_poll_timeout(priv->ctrl,
+				lane->ctrl_off + PCIE_STTS0,
+				val, (val & PM_REQ_CORE_RST) == 0,
+				PHY_INIT_WAIT_USLEEP_MAX,
+				PHY_INIT_WAIT_TIMEOUT);
+		if (ret) {
+			dev_err(priv->dev, "PM_REQ_CORE_RST is set\n");
+			return ret;
+		}
+	}
+
+	/* Polling to check the PHY is ready or not. */
+	if (lane->idx == 1)
+		cond = LANE1_TX_PLL_LOCK;
+	else
+		cond = LANE0_TX_PLL_LOCK;
+
+	ret = regmap_read_poll_timeout(priv->phy, lane->phy_off + PHY_STTS0,
+			val, ((val & cond) == cond),
+			PHY_INIT_WAIT_USLEEP_MAX, PHY_INIT_WAIT_TIMEOUT);
+	if (ret)
+		dev_err(priv->dev, "IMX8Q PHY%d PLL lock timeout\n", lane->idx);
+	else
+		dev_info(priv->dev, "IMX8Q PHY%d PLL is locked\n", lane->idx);
+
+	if (lane->lane_mode == PHY_MODE_SATA) {
+		cond = REG48_PMA_RDY;
+		ret = read_poll_timeout(readb, val, ((val & cond) == cond),
+				PHY_INIT_WAIT_USLEEP_MAX, PHY_INIT_WAIT_TIMEOUT,
+				false, priv->base + REG48_PMA_STATUS);
+		if (ret)
+			dev_err(priv->dev, "PHY calibration is timeout\n");
+		else
+			dev_info(priv->dev, "PHY calibration is done\n");
+	}
+
+	return ret;
+}
+
+static int imx8q_hsio_set_mode(struct phy *phy, enum phy_mode mode,
+				   int submode)
+{
+	u32 val;
+	struct imx8q_hsio_lane *lane = phy_get_drvdata(phy);
+	struct imx8q_hsio_priv *priv = lane->priv;
+
+	if (lane->lane_mode != mode)
+		return -EINVAL;
+
+	val = (mode == PHY_MODE_PCIE) ? MODE_PCIE : MODE_SATA;
+	val = FIELD_PREP(MODE_MASK, val);
+	regmap_update_bits(priv->phy, lane->phy_off + CTRL0, MODE_MASK, val);
+
+	switch (submode) {
+	case PHY_MODE_PCIE_RC:
+		val = FIELD_PREP(DEVICE_TYPE_MASK, PCI_EXP_TYPE_ROOT_PORT);
+		break;
+	case PHY_MODE_PCIE_EP:
+		val = FIELD_PREP(DEVICE_TYPE_MASK, PCI_EXP_TYPE_ENDPOINT);
+		break;
+	default: /* Support only PCIe EP and RC now. */
+		return 0;
+	}
+	if (submode)
+		regmap_update_bits(priv->ctrl, lane->ctrl_off + CTRL0,
+				   DEVICE_TYPE_MASK, val);
+
+	return 0;
+}
+
+static int imx8q_hsio_set_speed(struct phy *phy, int speed)
+{
+	struct imx8q_hsio_lane *lane = phy_get_drvdata(phy);
+	struct imx8q_hsio_priv *priv = lane->priv;
+
+	regmap_update_bits(priv->ctrl, lane->ctrl_off + CTRL2, LTSSM_ENABLE,
+			   speed ? LTSSM_ENABLE : 0);
+	return 0;
+}
+
+static const struct phy_ops imx8q_hsio_ops = {
+	.init = imx8q_hsio_init,
+	.exit = imx8q_hsio_exit,
+	.power_on = imx8q_hsio_power_on,
+	.set_mode = imx8q_hsio_set_mode,
+	.set_speed = imx8q_hsio_set_speed,
+	.owner = THIS_MODULE,
+};
+
+static const struct imx8q_hsio_drvdata imx8qxp_serdes_drvdata = {
+	.num_lane = 1,
+};
+
+static const struct imx8q_hsio_drvdata imx8qm_serdes_drvdata = {
+	.num_lane = 3,
+};
+
+static const struct of_device_id imx8q_hsio_of_match[] = {
+	{.compatible = "fsl,imx8qxp-serdes", .data = &imx8qxp_serdes_drvdata},
+	{.compatible = "fsl,imx8qm-serdes", .data = &imx8qm_serdes_drvdata},
+	{ },
+};
+
+MODULE_DEVICE_TABLE(of, imx8q_hsio_of_match);
+
+static struct phy *imx8q_hsio_xlate(struct device *dev,
+				    struct of_phandle_args *args)
+{
+	struct imx8q_hsio_priv *priv = dev_get_drvdata(dev);
+	int idx = args->args[0];
+	int ctrl_id = args->args[1];
+	int hsio_cfg = args->args[2];
+
+	if (idx >= priv->drvdata->num_lane)
+		return ERR_PTR(-EINVAL);
+	priv->lane[idx].idx = idx;
+	priv->lane[idx].ctrl_id = ctrl_id;
+	priv->hsio_cfg = hsio_cfg;
+
+	return priv->lane[idx].phy;
+}
+
+static int imx8q_hsio_probe(struct platform_device *pdev)
+{
+	int i;
+	void __iomem *off;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	const struct of_device_id *of_id;
+	struct imx8q_hsio_priv *priv;
+	struct phy_provider *provider;
+
+	of_id = of_match_device(imx8q_hsio_of_match, dev);
+	if (!of_id)
+		return -EINVAL;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	priv->dev = &pdev->dev;
+	priv->drvdata = of_device_get_match_data(dev);
+
+	/* Get PHY refclk pad mode */
+	of_property_read_u32(np, "fsl,refclk-pad-mode", &priv->refclk_pad_mode);
+
+	priv->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	off = devm_platform_ioremap_resource_byname(pdev, "phy");
+	priv->phy = devm_regmap_init_mmio(dev, off, &regmap_config);
+	if (IS_ERR(priv->phy))
+		return dev_err_probe(dev, PTR_ERR(priv->phy),
+				     "unable to find phy csr registers\n");
+
+	off = devm_platform_ioremap_resource_byname(pdev, "ctrl");
+	priv->ctrl = devm_regmap_init_mmio(dev, off, &regmap_config);
+	if (IS_ERR(priv->ctrl))
+		return dev_err_probe(dev, PTR_ERR(priv->ctrl),
+				     "unable to find ctrl csr registers\n");
+
+	off = devm_platform_ioremap_resource_byname(pdev, "misc");
+	priv->misc = devm_regmap_init_mmio(dev, off, &regmap_config);
+	if (IS_ERR(priv->misc))
+		return dev_err_probe(dev, PTR_ERR(priv->misc),
+				     "unable to find misc csr registers\n");
+
+	for (i = 0; i < priv->drvdata->num_lane; i++) {
+		struct imx8q_hsio_lane *lane = &priv->lane[i];
+		struct phy *phy;
+
+		memset(lane, 0, sizeof(*lane));
+
+		phy = devm_phy_create(&pdev->dev, NULL, &imx8q_hsio_ops);
+		if (IS_ERR(phy))
+			return PTR_ERR(phy);
+
+		lane->priv = priv;
+		lane->phy = phy;
+		lane->idx = i;
+		phy_set_drvdata(phy, lane);
+	}
+
+	dev_set_drvdata(dev, priv);
+	dev_set_drvdata(&pdev->dev, priv);
+
+	provider = devm_of_phy_provider_register(&pdev->dev, imx8q_hsio_xlate);
+
+	return PTR_ERR_OR_ZERO(provider);
+}
+
+static struct platform_driver imx8q_hsio_driver = {
+	.probe	= imx8q_hsio_probe,
+	.driver = {
+		.name	= "imx8q-hsio-phy",
+		.of_match_table	= imx8q_hsio_of_match,
+	}
+};
+module_platform_driver(imx8q_hsio_driver);
+
+MODULE_DESCRIPTION("FSL IMX8Q HSIO SERDES PHY driver");
+MODULE_LICENSE("GPL");
-- 
2.37.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* Re: [PATCH REVIEW] hwrng: add exynos Secure World RNG device driver
From: Gowthami Thiagarajan @ 2024-03-29  7:55 UTC (permalink / raw)
  To: Alexey Klimov
  Cc: olivia, herbert, sehi.kim, linux-samsung-soc, peter.griffin,
	krzysztof.kozlowski, alim.akhtar, linux-crypto, linux-arm-kernel,
	linux-kernel, kernel-team, andre.draszik, willmcvicker, saravanak,
	elder, tudor.ambarus, klimov.linux
In-Reply-To: <20240328125056.1054878-1-alexey.klimov@linaro.org>

On 2024-03-28 at 18:20:56, Alexey Klimov (alexey.klimov@linaro.org) wrote:
> The Exynos TRNG device is controlled by firmware and shared between
> non-secure world and secure world. Access to it is exposed via SMC
> interface which is implemented here. The firmware code does
> additional security checks, start-up test and some checks on resume.
> 
> This device is found, for instance, in Google Tensor GS101-family
> of devices.
> 
> Signed-off-by: Alexey Klimov <alexey.klimov@linaro.org>
> ---
Hi Alexey Klimov,

Please find few comments inline.

>  drivers/char/hw_random/Kconfig           |  12 +
>  drivers/char/hw_random/Makefile          |   1 +
>  drivers/char/hw_random/exynos-swd-trng.c | 423 +++++++++++++++++++++++
>  3 files changed, 436 insertions(+)
>  create mode 100644 drivers/char/hw_random/exynos-swd-trng.c
> 
> diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
> index 442c40efb200..bff7c3ec129a 100644
> --- a/drivers/char/hw_random/Kconfig
> +++ b/drivers/char/hw_random/Kconfig
> @@ -479,6 +479,18 @@ config HW_RANDOM_EXYNOS
>  
>  	  If unsure, say Y.
>  
> +config HW_RANDOM_EXYNOS_SWD
> +	tristate "Exynos SWD HW random number generator support"
> +	default n
> +	help
> +	  This driver provides kernel-side support for accessing Samsung
> +	  TRNG hardware located in secure world using smc calls.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called exynos-swd-trng.
> +
> +	  If unsure, say N.
> +
>  config HW_RANDOM_OPTEE
>  	tristate "OP-TEE based Random Number Generator support"
>  	depends on OPTEE
> diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
> index 32549a1186dc..ce64929d461a 100644
> --- a/drivers/char/hw_random/Makefile
> +++ b/drivers/char/hw_random/Makefile
> @@ -15,6 +15,7 @@ obj-$(CONFIG_HW_RANDOM_N2RNG) += n2-rng.o
>  n2-rng-y := n2-drv.o n2-asm.o
>  obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o
>  obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-trng.o
> +obj-$(CONFIG_HW_RANDOM_EXYNOS_SWD) += exynos-swd-trng.o
>  obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o
>  obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
>  obj-$(CONFIG_HW_RANDOM_OMAP3_ROM) += omap3-rom-rng.o
> diff --git a/drivers/char/hw_random/exynos-swd-trng.c b/drivers/char/hw_random/exynos-swd-trng.c
> new file mode 100644
> index 000000000000..29def8e6d0b7
> --- /dev/null
> +++ b/drivers/char/hw_random/exynos-swd-trng.c
> @@ -0,0 +1,423 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * exynos-swd-trng.c - Random Number Generator driver for the exynos TRNG
> + * located in secure world
> + * Copyright (C) Linaro Ltd 2024 Alexey Klimov <alexey.klimov@linaro.org>
> + *
> + * Based on downstream driver:
> + * Copyright (C) 2018 Samsung Electronics
> + * Sehee Kim <sehi.kim@samsung.com>
> + */
> +
> +#include <linux/arm-smccc.h>
> +#include <linux/delay.h>
> +#include <linux/hw_random.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +
> +/* DTRNG smc */
> +#define SMC_CMD_RANDOM			(0x82001012)
> +
> +/* DTRNG smc commands */
> +#define HWRNG_INIT			(0x0)
> +#define HWRNG_EXIT			(0x1)
> +#define HWRNG_GET_DATA			(0x2)
> +#define HWRNG_RESUME			(0x3)
> +
> +#define HWRNG_RET_OK			0
> +#define HWRNG_RET_INVALID_ERROR		1
> +#define HWRNG_RET_RETRY_ERROR		2
> +#define HWRNG_RET_INVALID_FLAG_ERROR	3
> +#define HWRNG_RET_TEST_ERROR		4
> +#define HWRNG_RET_START_UP_TEST_DONE	5
> +#define HWRNG_RET_TEST_KAT_ERROR	0xC
> +
> +#define EXYRNG_START_UP_SIZE		(4096 + 1)
> +#define EXYRNG_RETRY_MAX_COUNT		1000000
> +#define EXYRNG_START_UP_TEST_MAX_RETRY	2
> +
> +#define DRVNAME	"exynos_swd_trng"
> +
> +enum state {
> +	INACTIVE = 0,
> +	ACTIVE,
> +};
> +
> +struct exyswd_rng {
> +	struct hwrng rng;
> +	enum state state;
> +	struct device *dev;
> +	/* to track and protect state of the device */
> +	struct mutex lock;
> +};
> +
> +static int __exynos_cm_smc(u64 *arg0, u64 *arg1,
> +			   u64 *arg2, u64 *arg3)
> +{
> +	struct arm_smccc_res res;
> +
> +	arm_smccc_smc(*arg0, *arg1, *arg2, *arg3, 0, 0, 0, 0, &res);
> +
> +	*arg0 = res.a0;
> +	*arg1 = res.a1;
> +	*arg2 = res.a2;
> +	*arg3 = res.a3;
> +
> +	return *arg0;
> +}
> +
> +static int exynos_cm_cmd(int cmd)
> +{
> +	u64 reg0, reg1, reg2, reg3;
> +
> +	reg0 = SMC_CMD_RANDOM;
> +	reg1 = cmd;
> +	reg3 = reg2 = 0;
> +
> +	return __exynos_cm_smc(&reg0, &reg1, &reg2, &reg3);
> +}
> +
> +static int exynos_cm_get_data(u64 *arg0, u64 *arg1,
> +			      u64 *arg2, u64 *arg3)
> +{
> +	*arg0 = SMC_CMD_RANDOM;
> +	*arg1 = HWRNG_GET_DATA;
> +	*arg3 = 0;
> +
> +	return __exynos_cm_smc(arg0, arg1, arg2, arg3);
> +}

Can you avoid implementing specific SMC calls in this driver?
Instead, is it possible to use arm_smccc_1_1_invoke passing
corresponding arguements?

> +
> +static int exynos_swd_get_data(u64 *arg0, u64 *arg1, u64 *arg2, u64 *arg3,
> +			       struct exyswd_rng *exyswd_rng)
> +{
> +	u32 retry_cnt = 0;
> +	int ret;
> +
> +	while (retry_cnt++ < EXYRNG_RETRY_MAX_COUNT) {
> +		ret = exynos_cm_get_data(arg0, arg1, arg2, arg3);
> +
> +		if (ret == HWRNG_RET_OK)
> +			return 0;
> +
> +		if (ret == HWRNG_RET_RETRY_ERROR) {
> +			usleep_range(50, 100);
> +			continue;
> +		}
> +
> +		if (ret == HWRNG_RET_TEST_ERROR) {
> +			dev_dbg(exyswd_rng->dev, "error while testing\n");
> +			return -EAGAIN;
> +		}
> +
> +		return -EFAULT;
> +	}
> +
> +	ret = -EFAULT;
> +	dev_warn(exyswd_rng->dev, "retry counter is reached\n");
> +	return ret;
> +}
> +
> +static int exynos_swd_init(void)
> +{
> +	u32 retry_cnt = 0;
> +	int ret;
> +
> +	do {
> +		ret = exynos_cm_cmd(HWRNG_INIT);
> +		if (ret == HWRNG_RET_RETRY_ERROR) {
> +			if (retry_cnt++ > EXYRNG_RETRY_MAX_COUNT)
> +				break;
> +
> +			usleep_range(50, 100);
> +		}
> +	} while (ret == HWRNG_RET_RETRY_ERROR);
> +
> +	return ret;
> +}
> +
> +static void exynos_swd_exit(void)
> +{
> +	u32 retry_cnt = 0;
> +
> +	while (retry_cnt++ < EXYRNG_RETRY_MAX_COUNT) {
> +		if (!exynos_cm_cmd(HWRNG_EXIT))
> +			break;
> +		usleep_range(50, 100);
> +	}
> +}
> +
> +static int exynos_swd_startup_test(struct exyswd_rng *exyswd_rng)
> +{
> +	u64 reg0, reg1, reg2, reg3;
> +	int start_up_size = EXYRNG_START_UP_SIZE;
> +	u32 retry_cnt = 0;
> +	int ret;
> +
> +	ret = exynos_swd_init();
> +	if (ret != HWRNG_RET_OK) {
> +		if (ret == HWRNG_RET_TEST_ERROR) {
> +			ret = -EAGAIN;
> +			goto out;
> +		} else
> +			return -EFAULT;
> +	}
> +
> +	while (start_up_size > 0) {
> +		/* For start-up test the 3-rd argument has to be set to 1 */
> +		reg2 = 1;

Can this be changed to a #define constant for better clarity?

> +		ret = exynos_cm_get_data(&reg0, &reg1, &reg2, &reg3);
> +		if (ret == HWRNG_RET_RETRY_ERROR) {
> +			if (retry_cnt++ > EXYRNG_RETRY_MAX_COUNT) {
> +				dev_warn(exyswd_rng->dev,
> +					 "exceeded retry in start-up test\n");
> +				break;
> +			}
> +			usleep_range(50, 100);
> +			continue;
> +		}
> +
> +		if (ret == HWRNG_RET_TEST_ERROR ||
> +		    ret == HWRNG_RET_TEST_KAT_ERROR) {
> +			dev_err(exyswd_rng->dev,
> +				"malfunction of TRNG(HW) is detected\n");
> +			return -EFAULT;
> +		}
> +
> +		if (ret == HWRNG_RET_START_UP_TEST_DONE) {
> +			dev_dbg(exyswd_rng->dev,
> +				"start-up test is already done\n");
> +			ret = 0;
> +			break;
> +		}
> +
> +		if (ret != HWRNG_RET_OK) {
> +			dev_dbg(exyswd_rng->dev, "failed to get random data\n");
> +			return -EFAULT;
> +		}
> +
> +		start_up_size -= 32;
Similar to the above, please change this. And why 32 bytes?

> +		retry_cnt = 0;
> +	}
> +
> +out:
> +	exynos_swd_exit();
> +	return ret;
> +}
> +
> +static int exynos_swd_read(struct hwrng *rng, void *data, size_t max, bool wait)
> +{
> +	struct exyswd_rng *exyswd_rng =
> +				container_of(rng, struct exyswd_rng, rng);
> +	u64 reg0, reg1, reg2, reg3;
> +	u32 *read_buf = data;
> +	u32 read_size = max;
> +	u32 retry_cnt;
> +	int ret = HWRNG_RET_OK;
> +
> +	mutex_lock(&exyswd_rng->lock);
> +	ret = exynos_swd_init();
> +	if (ret != HWRNG_RET_OK) {
> +		if (ret == HWRNG_RET_TEST_ERROR) {
> +			ret = -EAGAIN;
> +			goto out_locked;
> +		} else {
> +			mutex_unlock(&exyswd_rng->lock);
> +			return -EFAULT;
> +		}
> +	}
> +
> +	exyswd_rng->state = ACTIVE;
> +	mutex_unlock(&exyswd_rng->lock);
> +
> +	retry_cnt = 0;
> +	while (read_size >= 8) {
> +		reg2 = 0;
> +		ret = exynos_swd_get_data(&reg0, &reg1, &reg2, &reg3, exyswd_rng);
> +		if (ret)
> +			goto out;
> +
> +		*(u32 *)(read_buf++) = (u32)reg2;
> +		*(u32 *)(read_buf++) = (u32)reg3;
> +
> +		read_size -= 8;
> +		retry_cnt = 0;
> +	}
> +
> +	/*
> +	 * rng_buf_size is 32 bytes or cache line usually, it is unlikely
> +	 * we will have remaining bytes to read here.
> +	 */
> +	if (unlikely(read_size > 0)) {
> +		reg2 = 0;
> +		ret = exynos_swd_get_data(&reg0, &reg1, &reg2, &reg3, exyswd_rng);
> +		if (ret)
> +			goto out;
> +		if (read_size >= 4) {
> +			*(u32 *)(read_buf++) = (u32)reg2;
> +			read_size -= 4;
> +		}
> +
> +		if (read_size) {
> +			memcpy(read_buf, &reg3, read_size);
> +			read_size = 0;
> +		}
> +	}
> +
> +	ret = max;
> +out:
> +	mutex_lock(&exyswd_rng->lock);
> +out_locked:
> +	exynos_swd_exit();
> +	exyswd_rng->state = INACTIVE;
> +	mutex_unlock(&exyswd_rng->lock);
> +
> +	return ret;
> +}
> +
> +static int exyswd_rng_probe(struct platform_device *pdev)
> +{
> +	struct exyswd_rng *exyswd_rng;
> +	int ret;
> +
> +	exyswd_rng = devm_kzalloc(&pdev->dev, sizeof(*exyswd_rng), GFP_KERNEL);
> +	if (!exyswd_rng)
> +		return -ENOMEM;
> +
> +	exyswd_rng->rng.name = DRVNAME;
> +	exyswd_rng->rng.read = exynos_swd_read;
> +	exyswd_rng->rng.quality = 500;
> +	exyswd_rng->dev = &pdev->dev;
> +	exyswd_rng->state = INACTIVE;
> +	mutex_init(&exyswd_rng->lock);
> +
> +	/*
> +	 * Do the startup test first. If it works we've got the device
> +	 * and can finish probe().
> +	 */
> +	ret = exynos_swd_startup_test(exyswd_rng);
> +	if (ret) {
> +		dev_dbg(&pdev->dev, "start-up test failed\n");
> +		return -ENODEV;
> +	}
> +
> +	ret = devm_hwrng_register(&pdev->dev, &exyswd_rng->rng);
> +	if (ret)
> +		return dev_err_probe(&pdev->dev, ret,
> +				     "failed to register hwrng\n");
> +
> +	platform_set_drvdata(pdev, exyswd_rng);
> +	dev_set_drvdata(&pdev->dev, exyswd_rng);
> +
> +	dev_info(&pdev->dev, "hwrng registered\n");
> +
> +	return 0;
> +}
> +
> +static int exyswd_rng_remove(struct platform_device *pdev)
> +{
> +	struct exyswd_rng *exyswd_rng = platform_get_drvdata(pdev);
> +
> +	devm_hwrng_unregister(&pdev->dev, &exyswd_rng->rng);
> +
> +	mutex_lock(&exyswd_rng->lock);
> +	if (exyswd_rng->state == ACTIVE) {
> +		exynos_swd_exit();
> +		exyswd_rng->state = INACTIVE;
> +	}
> +	mutex_unlock(&exyswd_rng->lock);
> +
> +	return 0;
> +}
> +
> +#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME)
> +static int exyswd_rng_suspend(struct device *dev)
> +{
> +	struct exyswd_rng *exyswd_rng = dev_get_drvdata(dev);
> +	int ret = 0;
> +
> +	mutex_lock(&exyswd_rng->lock);
> +	if (exyswd_rng->state) {
> +		ret = exynos_cm_cmd(HWRNG_EXIT);
> +		if (ret != HWRNG_RET_OK)
> +			dev_warn(dev,
> +				 "failed to enter suspend, error %d\n", ret);
> +	}
> +	mutex_unlock(&exyswd_rng->lock);
> +
> +	return ret;
> +}
> +
> +static int exyswd_rng_resume(struct device *dev)
> +{
> +	struct exyswd_rng *exyswd_rng = dev_get_drvdata(dev);
> +	int ret;
> +
> +	mutex_lock(&exyswd_rng->lock);
> +	ret = exynos_cm_cmd(HWRNG_RESUME);
> +	if (ret != HWRNG_RET_OK)
> +		dev_warn(dev, "failed to resume, error %d\n", ret);
> +	if (exyswd_rng->state) {
> +		ret = exynos_cm_cmd(HWRNG_INIT);
> +		if (ret != HWRNG_RET_OK)
> +			dev_warn(dev,
> +				 "failed to init hwrng on resume, error %d\n",
> +				 ret);
> +	}
> +	mutex_unlock(&exyswd_rng->lock);
> +
> +	return ret;
> +}
> +#endif
> +
> +static UNIVERSAL_DEV_PM_OPS(exyswd_rng_pm_ops, exyswd_rng_suspend,
> +			    exyswd_rng_resume, NULL);
> +
> +static struct platform_driver exyswd_rng_driver = {
> +	.probe		= exyswd_rng_probe,
> +	.remove		= exyswd_rng_remove,
> +	.driver		= {
> +		.name	= DRVNAME,
> +		.owner	= THIS_MODULE,
> +		.pm     = &exyswd_rng_pm_ops,
> +	},
> +};
> +
> +static struct platform_device *exyswd_rng_pdev;
> +
> +static int __init exyswd_rng_init(void)
> +{
> +	int ret;
> +
> +	exyswd_rng_pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0);
> +	if (IS_ERR(exyswd_rng_pdev))
> +		pr_err(DRVNAME ": could not register device: %ld\n",
> +		       PTR_ERR(exyswd_rng_pdev));
> +
> +	ret = platform_driver_register(&exyswd_rng_driver);
> +	if (ret) {
> +		platform_device_unregister(exyswd_rng_pdev);
> +		return ret;
> +	}
> +
> +	pr_info("ExyRNG driver, (c) 2014 Samsung Electronics\n");
> +
> +	return 0;
> +}
> +
> +static void __exit exyswd_rng_exit(void)
> +{
> +	platform_driver_unregister(&exyswd_rng_driver);
> +	platform_device_unregister(exyswd_rng_pdev);
> +}
> +
> +module_init(exyswd_rng_init);
> +module_exit(exyswd_rng_exit);
> +
> +MODULE_DESCRIPTION("Exynos SWD H/W Random Number Generator driver");
> +MODULE_AUTHOR("Alexey Klimov <alexey.klimov@linaro.org>");
> +MODULE_AUTHOR("Sehee Kim <sehi.kim@samsung.com>");
> +MODULE_LICENSE("GPL");
> -- 
> 2.43.0
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [Upstream] [PATCH 0/2] i.MX93 ADC calibration settings
From: Primoz Fiser @ 2024-03-29  7:58 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Andrej Picej, Jonathan Cameron, devicetree, conor+dt, lars,
	krzysztof.kozlowski+dt, imx, linux-iio, festevam, s.hauer,
	upstream, linux-kernel, haibo.chen, kernel, shawnguo, robh,
	linux-arm-kernel
In-Reply-To: <20240325144555.00002d16@Huawei.com>

Hi Jonathan,

On 25. 03. 24 15:45, Jonathan Cameron wrote:
> On Mon, 25 Mar 2024 09:55:23 +0100
> Primoz Fiser <primoz.fiser@norik.com> wrote:
> 
>> Hi Jonathan,
>>
>> On 25. 03. 24 09:32, Andrej Picej wrote:
>>> Hi Jonathan,
>>>
>>> On 24. 03. 24 14:55, Jonathan Cameron wrote:  
>>>> On Wed, 20 Mar 2024 11:04:04 +0100
>>>> Andrej Picej <andrej.picej@norik.com> wrote:
>>>>  
>>>>> Hi all,
>>>>>
>>>>> we had some problems with failing ADC calibration on the i.MX93 boards.
>>>>> Changing default calibration settings fixed this. The board where this
>>>>> patches are useful is not yet upstream but will be soon (hopefully).  
>>>>
>>>> Tell us more.  My initial instinct is that this shouldn't be board
>>>> specific.
>>>> What's the trade off we are making here?  Time vs precision of
>>>> calibration or
>>>> something else?  If these are set to a level by default that doesn't work
>>>> for our board, maybe we should just change them for all devices?
>>>>  
>>
>> The imx93_adc driver is quite new.
>>
>> If you look at line #162, you will find a comment by the original author:
>>
>>> 	/*
>>> 	 * TODO: we use the default TSAMP/NRSMPL/AVGEN in MCR,
>>> 	 * can add the setting of these bit if need in future.
>>> 	 */  
>>
>> URL:
>> https://github.com/torvalds/linux/blob/master/drivers/iio/adc/imx93_adc.c#L162
>>
>> So, for most use-cases the default setting should work, but why not make
>> them configurable?
>>
>> So this patch-series just implement what was missing from the beginning
>> / was planned for later.
> Hi Primoz,
> 
> I doubt anyone reviewed the comment closely enough to say if what it was
> suggesting was sensible or not, so the fact it was listed as a todo
> doesn't directly impact this discussion.

I agree.

However on the other hand, since we stumbled upon a use-case that
requires adjusting the driver provided default settings of the i.MX93
ADC, this TODO to us is and was a clear indication from the original
author that the driver needs little TLC.

Anyhow, a stance from the author/NXP would be highly welcoming in this
situation.

BR,
Primoz


> 
>>
>> BR,
>> Primoz
>>
>>
>>>
>>> So we have two different boards with the same SoC. On one, the
>>> calibration works with the default values, on the second one the
>>> calibration fails, which makes the ADC unusable. What the ADC lines
>>> measure differ between the boards though. But the implementation is
>>> nothing out of the ordinary.
>>>
>>> We tried different things but the only thing that helped is to use
>>> different calibration properties. We tried deferring the probe and
>>> calibration until later boot and after boot, but it did not help.
>>>
>>> In the Reference Manual [1] (chapter 72.5.1) it is written:
>>>   
>>>> 4. Configure desired calibration settings (default values kept for
>>>> highest accuracy maximum time).  
>>>
>>> So your assumption is correct, longer calibration time (more averaging
>>> samples) -> higher precision. The default values go for a high accuracy.
>>> And since we use a NRSMPL (Number of Averaging Samples) of 32 instead of
>>> default 512, we reduce the accuracy so the calibration values pass the
>>> internal defined limits.
> 
> Ouch.  Let me try to dig into this. Is this effectively relaxing the
> constraints? I guess because a value that is perhaps always biased one way
> is considered within bounds if those acceptable bounds are wider because
> of lower precision?
> 
> I was assuming it was the other way around and the device had fixed constraint
> limits and you needed to take more samples due to higher noise. Seems the
> opposite is true here and that worries me.
> 
> I'll definitely need input from NXP on this as a workaround and their
> strong support to consider it.
> 
>>>
>>> I'm not sure that changing default values is the right solution here. We
>>> saw default values work with one of the boards. And since the NXP kept
>>> these values adjustable I think there is a reason behind it.
> 
> I'd assume trade off between time and calibration precision, not the
> sort of use I think you are describing.
> 
>>>
>>> Note: When I say one of the boards I mean one board form. So same board
>>> version, but different HW.
> 
> Superficially I'm struggling to not see this as broken hardware that it
> is out of expected tolerances in some fashion.  Maybe I misunderstood
> the issue.
> 
> Jonathan
> 
>>>
>>> Best regards,
>>> Andrej
>>>
>>> [1] i.MX 93 Applications Processor Reference Manual, Rev. 4, 12/2023
>>> _______________________________________________
>>> upstream mailing list
>>> upstream@lists.phytec.de
>>> http://lists.phytec.de/cgi-bin/mailman/listinfo/upstream  
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

-- 
Primoz Fiser                    | phone: +386-41-390-545
<tel:+386-41-390-545> |
---------------------------------------------------------|
Norik systems d.o.o.            | https://www.norik.com
<https://www.norik.com>  |
Your embedded software partner  | email: info@norik.com
<mailto:info@norik.com> |
Slovenia, EU                    | phone: +386-41-540-545
<tel:+386-41-540-545> |


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v6 3/3] pinctrl: nuvoton: Add ma35d1 pinctrl and GPIO driver
From: Jacky Huang @ 2024-03-29  8:17 UTC (permalink / raw)
  To: Linus Walleij
  Cc: robh+dt, krzysztof.kozlowski+dt, conor+dt, p.zabel, j.neuschaefer,
	linux-arm-kernel, linux-gpio, devicetree, linux-kernel, ychuang3,
	schung
In-Reply-To: <CACRpkdYnG+SgrgAWW8+qdiBwO5d+nE8g_31Evyw0pA2dXz3BPw@mail.gmail.com>


Dear Linus,

Thanks for your review.


On 2024/3/28 下午 05:10, Linus Walleij wrote:
> Hi Jacky,
>
> overall this looks very good.
>
> On Wed, Mar 13, 2024 at 4:57 AM Jacky Huang <ychuang570808@gmail.com> wrote:
>
>
>> From: Jacky Huang <ychuang3@nuvoton.com>
>>
>> Add common pinctrl and GPIO driver for Nuvoton MA35 series SoC, and
>> add support for ma35d1 pinctrl.
>>
>> Signed-off-by: Jacky Huang <ychuang3@nuvoton.com>
> (...)
>> +static int ma35_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int selector,
>> +                              unsigned int group)
>> +{
>> +       struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev);
>> +       struct ma35_pin_group *grp = &npctl->groups[group];
>> +       struct ma35_pin_setting *setting = grp->settings;
>> +       u32 i, regval;
>> +
>> +       dev_dbg(npctl->dev, "enable function %s group %s\n",
>> +               npctl->functions[selector].name, npctl->groups[group].name);
>> +
>> +       for (i = 0; i < grp->npins; i++) {
>> +               regmap_read(npctl->regmap, setting->offset, &regval);
>> +               regval &= ~GENMASK(setting->shift + 3, setting->shift);
> Add a comment explaining why you add +3

The pinmux selection is 4 bits. I will use a constant for the bitmask 
width instead.

>
>> +static int ma35_gpio_core_direction_in(struct gpio_chip *gc, unsigned int gpio)
>> +{
>> +       struct ma35_pin_bank *bank = gpiochip_get_data(gc);
>> +       void __iomem *reg_mode = bank->reg_base + MA35_GP_REG_MODE;
>> +       unsigned long flags;
>> +       unsigned int regval;
>> +
>> +       spin_lock_irqsave(&bank->lock, flags);
>> +
>> +       regval = readl(reg_mode);
>> +       regval &= ~GENMASK(gpio * 2 + 1, gpio * 2);
>> +       regval |= MA35_GP_MODE_INPUT << gpio * 2;
> Here the first time you do this magic explain in a comment why you
> use *2+1 and *2 overall (I guess two bits per line).

Yes, it is two bits per pin. I will add a comment to explain this.

>> +static int ma35_gpio_core_get(struct gpio_chip *gc, unsigned int gpio)
>> +{
>> +       struct ma35_pin_bank *bank = gpiochip_get_data(gc);
>> +
>> +       return readl(bank->reg_base + MA35_PIN_MAP_BASE + gpio * 4);
> Here add a comment explaining the *4
> I guess one 32-bit register per pin?

Yes, it maps one 32-bit register to a gpio pin.
I will add a comment to explain this.

>> +static int ma35_irq_irqtype(struct irq_data *d, unsigned int type)
>> +{
>> +       struct ma35_pin_bank *bank = gpiochip_get_data(irq_data_get_irq_chip_data(d));
>> +       void __iomem *reg_itype = bank->reg_base + MA35_GP_REG_INTTYPE;
>> +       void __iomem *reg_ien = bank->reg_base + MA35_GP_REG_INTEN;
>> +       unsigned int num = (d->hwirq);
>> +
>> +       if (type == IRQ_TYPE_PROBE) {
>> +               writel(readl(reg_itype) & ~BIT(num), reg_itype);
>> +               writel(readl(reg_ien) | BIT(num) | BIT(num + 16), reg_ien);
>> +               bank->irqtype &= ~BIT(num);
>> +               bank->irqinten |= BIT(num) | BIT(num + 16);
>> +               return 0;
>> +       }
>> +
>> +       if (type & IRQ_TYPE_LEVEL_MASK) {
>> +               writel(readl(reg_itype) | BIT(num), reg_itype);
>> +               writel(readl(reg_ien) & ~(BIT(num) | BIT(num + 16)), reg_ien);
>> +               bank->irqtype |= BIT(num);
>> +               bank->irqinten &= ~(BIT(num) | BIT(num + 16));
>> +               if (type == IRQ_TYPE_LEVEL_HIGH) {
>> +                       writel(readl(reg_ien) | BIT(num + 16), reg_ien);
>> +                       bank->irqinten |= BIT(num + 16);
>> +                       return 0;
>> +               }
>> +
>> +               if (type == IRQ_TYPE_LEVEL_LOW) {
>> +                       writel(readl(reg_ien) | BIT(num), reg_ien);
>> +                       bank->irqinten |= BIT(num);
>> +                       return 0;
>> +               }
>> +
>> +       } else {
>> +               writel(readl(reg_itype) & ~BIT(num), reg_itype);
>> +               bank->irqtype &= ~BIT(num);
>> +
>> +               if (type & IRQ_TYPE_EDGE_RISING) {
>> +                       writel(readl(reg_ien) | BIT(num + 16), reg_ien);
>> +                       bank->irqinten |= BIT(num + 16);
>> +
>> +               } else {
>> +                       writel(readl(reg_ien) & ~BIT(num + 16), reg_ien);
>> +                       bank->irqinten &= ~BIT(num + 16);
>> +               }
>> +
>> +               if (type & IRQ_TYPE_EDGE_FALLING) {
>> +                       writel(readl(reg_ien) | BIT(num), reg_ien);
>> +                       bank->irqinten |= BIT(num);
>> +
>> +               } else {
>> +                       writel(readl(reg_ien) & ~BIT(num), reg_ien);
>> +                       bank->irqinten &= ~BIT(num);
>> +               }
>> +       }
>> +       return 0;
>> +}
> I don't understand why you don't set the irq_handler:
> irq_set_handler_locked(d, handle_edge_irq);
> irq_set_handler_locked(d, handle_level_irq);

I will add the irq_set_handler_locked().
> It seems you are not handling IRQ_TYPE_EDGE_BOTH?
> What happens if both rising and falling is specified simultaneously?
>
> The if/else nesting is hard to read.
> switch (type) {
>          case IRQ_TYPE_EDGE_BOTH:
> (...)
>          case IRQ_TYPE_EDGE_RISING:
> (...)
>
> See drivers/gpio/gpio-ftgpio010.c for an example.

We'll refer to this driver to modify our code.

> Have you checked that handling edge and level IRQs really work
> as expected?

This driver works with edge or level IRQs in linux-5.10, and some 
modifications
have been made for upstream. We'll verify if it also works in linux-6.9.

>> +static int ma35_gpiolib_register(struct platform_device *pdev, struct ma35_pinctrl *npctl)
>> +{
>> +       struct ma35_pin_ctrl *ctrl = npctl->ctrl;
>> +       struct ma35_pin_bank *bank = ctrl->pin_banks;
>> +       int ret;
>> +       int i;
>> +
>> +       for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
>> +               if (!bank->valid) {
>> +                       dev_warn(&pdev->dev, "bank %s is not valid\n",
>> +                                bank->np->name);
>> +                       continue;
>> +               }
>> +               bank->irqtype = 0;
>> +               bank->irqinten = 0;
>> +               bank->chip.label = bank->name;
>> +               bank->chip.of_gpio_n_cells = 2;
>> +               bank->chip.parent = &pdev->dev;
>> +               bank->chip.request = ma35_gpio_core_to_request;
>> +               bank->chip.direction_input = ma35_gpio_core_direction_in;
>> +               bank->chip.direction_output = ma35_gpio_core_direction_out;
>> +               bank->chip.get = ma35_gpio_core_get;
>> +               bank->chip.set = ma35_gpio_core_set;
>> +               bank->chip.base = -1;
>> +               bank->chip.ngpio = bank->nr_pins;
>> +               bank->chip.can_sleep = false;
>> +               spin_lock_init(&bank->lock);
>> +
>> +               if (bank->irq > 0) {
>> +                       struct gpio_irq_chip *girq;
>> +
>> +                       girq = &bank->chip.irq;
>> +                       gpio_irq_chip_set_chip(girq, &ma35_gpio_irqchip);
>> +                       girq->parent_handler = ma35_irq_demux_intgroup;
>> +                       girq->num_parents = 1;
>> +
>> +                       girq->parents = devm_kcalloc(&pdev->dev, 1, sizeof(*girq->parents),
>> +                                                    GFP_KERNEL);
>> +                       if (!girq->parents)
>> +                               return -ENOMEM;
>> +
>> +                       girq->parents[0] = bank->irq;
>> +                       girq->default_type = IRQ_TYPE_NONE;
>> +                       girq->handler = handle_level_irq;
> Does this really work for the edge IRQs?
>
> I recommend setting this to handle_bad_irq and assign the right
> handler in .set_type().
>
> Yours,
> Linus Walleij

OK, I will fix it.


Best Regards,
Jacky Huang





_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v3 3/4] PM: EM: Add em_dev_update_chip_binning()
From: kernel test robot @ 2024-03-29  8:20 UTC (permalink / raw)
  To: Lukasz Luba, linux-kernel, linux-pm, rafael
  Cc: oe-kbuild-all, lukasz.luba, dietmar.eggemann, linux-arm-kernel,
	sboyd, nm, linux-samsung-soc, daniel.lezcano, viresh.kumar,
	krzysztof.kozlowski, alim.akhtar, m.szyprowski, mhiramat
In-Reply-To: <20240328085112.3873050-4-lukasz.luba@arm.com>

Hi Lukasz,

kernel test robot noticed the following build warnings:

[auto build test WARNING on rafael-pm/linux-next]
[also build test WARNING on krzk/for-next clk/clk-next linus/master v6.9-rc1 next-20240328]
[cannot apply to soc/for-next rafael-pm/acpi-bus rafael-pm/devprop]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Lukasz-Luba/OPP-OF-Export-dev_opp_pm_calc_power-for-usage-from-EM/20240328-165357
base:   https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next
patch link:    https://lore.kernel.org/r/20240328085112.3873050-4-lukasz.luba%40arm.com
patch subject: [PATCH v3 3/4] PM: EM: Add em_dev_update_chip_binning()
config: i386-buildonly-randconfig-002-20240328 (https://download.01.org/0day-ci/archive/20240329/202403291602.UyrrrpzO-lkp@intel.com/config)
compiler: gcc-12 (Ubuntu 12.3.0-9ubuntu2) 12.3.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240329/202403291602.UyrrrpzO-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202403291602.UyrrrpzO-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> kernel/power/energy_model.c:814: warning: bad line:                                 information is present in the OPPs.


vim +814 kernel/power/energy_model.c

   811	
   812	/**
   813	 * em_dev_update_chip_binning() - Update Energy Model after the new voltage
 > 814					information is present in the OPPs.

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [v1 0/3] Add i.MX8Q HSIO PHY driver support
From: Richard Zhu @ 2024-03-29  8:09 UTC (permalink / raw)
  To: vkoul, kishon, robh+dt, krzysztof.kozlowski+dt, conor+dt,
	frank.li
  Cc: hongxing.zhu, linux-phy, devicetree, linux-arm-kernel,
	linux-kernel, kernel, linux-imx

v1 changes:
- Rebase to the 6.9-rc1, and constify of_phandle_args in xlate.
No other changes.

i.MX8Q HSIO module has PHY and mix control regions.
This patch-set adds i.MX8Q HSIO PHY driver support, and provides
standard PHY phandles that can be used by i.MX8Q PCIe or
SATA driver later.

[PATCH v1 1/3] dt-bindings: phy: Add i.MX8Q HSIO SerDes PHY binding
[PATCH v1 2/3] dt-bindings: phy: phy-imx8-pcie: Add binding for
[PATCH v1 3/3] phy: freescale: imx8q-hsio: Add i.MX8Q HSIO PHY driver

Documentation/devicetree/bindings/phy/fsl,imx8q-hsio.yaml | 143 ++++++++++++++++++++++++
drivers/phy/freescale/Kconfig                             |   8 ++
drivers/phy/freescale/Makefile                            |   1 +
drivers/phy/freescale/phy-fsl-imx8q-hsio.c                | 518 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
include/dt-bindings/phy/phy-imx8-pcie.h                   |  26 +++++
5 files changed, 696 insertions(+)

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH v1 1/3] dt-bindings: phy: Add i.MX8Q HSIO SerDes PHY binding
From: Richard Zhu @ 2024-03-29  8:09 UTC (permalink / raw)
  To: vkoul, kishon, robh+dt, krzysztof.kozlowski+dt, conor+dt,
	frank.li
  Cc: hongxing.zhu, linux-phy, devicetree, linux-arm-kernel,
	linux-kernel, kernel, linux-imx
In-Reply-To: <1711699790-16494-1-git-send-email-hongxing.zhu@nxp.com>

Add i.MX8QM and i.MX8QXP HSIO SerDes PHY binding.
- Use the controller ID to specify which controller is binded to the
PHY.
- Introduce one HSIO configuration, mandatory required to set
"PCIE_AB_SELECT" and "PHY_X1_EPCS_SEL" during the initialization.

Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
---
 .../bindings/phy/fsl,imx8q-hsio.yaml          | 143 ++++++++++++++++++
 1 file changed, 143 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/fsl,imx8q-hsio.yaml

diff --git a/Documentation/devicetree/bindings/phy/fsl,imx8q-hsio.yaml b/Documentation/devicetree/bindings/phy/fsl,imx8q-hsio.yaml
new file mode 100644
index 000000000000..506551d4d94a
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/fsl,imx8q-hsio.yaml
@@ -0,0 +1,143 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/fsl,imx8q-hsio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Freescale i.MX8Q SoC series HSIO SERDES PHY
+
+maintainers:
+  - Richard Zhu <hongxing.zhu@nxp.com>
+
+properties:
+  compatible:
+    enum:
+      - fsl,imx8qxp-serdes
+      - fsl,imx8qm-serdes
+  reg:
+    minItems: 4
+    maxItems: 4
+
+  "#phy-cells":
+    const: 3
+    description: |
+      The first number defines the ID of the PHY contained in the HSIO macro.
+      The second defines controller ID binded to the PHY. The third defines the
+      HSIO configuratons refer to the different use cases. They are defined in
+      dt-bindings/phy/phy-imx8-pcie.h
+
+  reg-names:
+    items:
+      - const: reg
+      - const: phy
+      - const: ctrl
+      - const: misc
+
+  clocks:
+    minItems: 5
+    maxItems: 14
+
+  clock-names:
+    minItems: 5
+    maxItems: 14
+
+  fsl,refclk-pad-mode:
+    description: |
+      Specifies the mode of the refclk pad used. It can be UNUSED(PHY
+      refclock is derived from SoC internal source), INPUT(PHY refclock
+      is provided externally via the refclk pad) or OUTPUT(PHY refclock
+      is derived from SoC internal source and provided on the refclk pad).
+      Refer include/dt-bindings/phy/phy-imx8-pcie.h for the constants
+      to be used.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [ 0, 1, 2 ]
+
+  power-domains:
+    description: |
+      i.MX8Q HSIO SerDes power domains. i.MX8QXP has one SerDes power domains.
+      And i.MX8QM has two.
+    minItems: 1
+    maxItems: 2
+
+required:
+  - compatible
+  - reg
+  - "#phy-cells"
+  - clocks
+  - clock-names
+  - fsl,refclk-pad-mode
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - fsl,imx8qxp-serdes
+    then:
+      properties:
+        clock-names:
+          items:
+            - const: apb_pclk0
+            - const: pclk0
+            - const: phy0_crr
+            - const: ctl0_crr
+            - const: misc_crr
+        power-domains:
+          minItems: 1
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - fsl,imx8qm-serdes
+    then:
+      properties:
+        clock-names:
+          items:
+            - const: pclk0
+            - const: pclk1
+            - const: apb_pclk0
+            - const: apb_pclk1
+            - const: pclk2
+            - const: epcs_tx
+            - const: epcs_rx
+            - const: apb_pclk2
+            - const: phy0_crr
+            - const: phy1_crr
+            - const: ctl0_crr
+            - const: ctl1_crr
+            - const: ctl2_crr
+            - const: misc_crr
+        power-domains:
+          minItems: 2
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/imx8-clock.h>
+    #include <dt-bindings/clock/imx8-lpcg.h>
+    #include <dt-bindings/firmware/imx/rsrc.h>
+    #include <dt-bindings/phy/phy-imx8-pcie.h>
+
+    serdes: phy@5f1a0000 {
+            compatible = "fsl,imx8qxp-serdes";
+            reg = <0x5f1a0000 0x10000>,
+                  <0x5f120000 0x10000>,
+                  <0x5f140000 0x10000>,
+                  <0x5f160000 0x10000>;
+            reg-names = "reg", "phy", "ctrl", "misc";
+            clocks = <&phyx1_lpcg IMX_LPCG_CLK_0>,
+                     <&phyx1_lpcg IMX_LPCG_CLK_4>,
+                     <&phyx1_crr1_lpcg IMX_LPCG_CLK_4>,
+                     <&pcieb_crr3_lpcg IMX_LPCG_CLK_4>,
+                     <&misc_crr5_lpcg IMX_LPCG_CLK_4>;
+            clock-names = "apb_pclk0", "pclk0", "phy0_crr", "ctl0_crr",
+                          "misc_crr";
+            power-domains = <&pd IMX_SC_R_SERDES_1>;
+            #phy-cells = <3>;
+            status = "disabled";
+    };
+...
-- 
2.37.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v1 3/3] phy: freescale: imx8q-hsio: Add i.MX8Q HSIO PHY driver support
From: Richard Zhu @ 2024-03-29  8:09 UTC (permalink / raw)
  To: vkoul, kishon, robh+dt, krzysztof.kozlowski+dt, conor+dt,
	frank.li
  Cc: hongxing.zhu, linux-phy, devicetree, linux-arm-kernel,
	linux-kernel, kernel, linux-imx
In-Reply-To: <1711699790-16494-1-git-send-email-hongxing.zhu@nxp.com>

Add i.MX8Q HSIO PHY driver support.
- Add one HSIO configuration property, that used to select the
"PCIE_AB_SELECT" and "PHY_X1_EPCS_SEL" during the initialization.

Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
---
 drivers/phy/freescale/Kconfig              |   8 +
 drivers/phy/freescale/Makefile             |   1 +
 drivers/phy/freescale/phy-fsl-imx8q-hsio.c | 518 +++++++++++++++++++++
 3 files changed, 527 insertions(+)
 create mode 100644 drivers/phy/freescale/phy-fsl-imx8q-hsio.c

diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig
index 853958fb2c06..bcddddef1cbb 100644
--- a/drivers/phy/freescale/Kconfig
+++ b/drivers/phy/freescale/Kconfig
@@ -35,6 +35,14 @@ config PHY_FSL_IMX8M_PCIE
 	  Enable this to add support for the PCIE PHY as found on
 	  i.MX8M family of SOCs.
 
+config PHY_FSL_IMX8Q_HSIO
+	tristate "Freescale i.MX8Q HSIO PHY"
+	depends on OF && HAS_IOMEM
+	select GENERIC_PHY
+	help
+	  Enable this to add support for the HSIO PHY as found on
+	  i.MX8Q family of SOCs.
+
 endif
 
 config PHY_FSL_LYNX_28G
diff --git a/drivers/phy/freescale/Makefile b/drivers/phy/freescale/Makefile
index cedb328bc4d2..db888c37fcf9 100644
--- a/drivers/phy/freescale/Makefile
+++ b/drivers/phy/freescale/Makefile
@@ -3,4 +3,5 @@ obj-$(CONFIG_PHY_FSL_IMX8MQ_USB)	+= phy-fsl-imx8mq-usb.o
 obj-$(CONFIG_PHY_MIXEL_LVDS_PHY)	+= phy-fsl-imx8qm-lvds-phy.o
 obj-$(CONFIG_PHY_MIXEL_MIPI_DPHY)	+= phy-fsl-imx8-mipi-dphy.o
 obj-$(CONFIG_PHY_FSL_IMX8M_PCIE)	+= phy-fsl-imx8m-pcie.o
+obj-$(CONFIG_PHY_FSL_IMX8Q_HSIO)	+= phy-fsl-imx8q-hsio.o
 obj-$(CONFIG_PHY_FSL_LYNX_28G)		+= phy-fsl-lynx-28g.o
diff --git a/drivers/phy/freescale/phy-fsl-imx8q-hsio.c b/drivers/phy/freescale/phy-fsl-imx8q-hsio.c
new file mode 100644
index 000000000000..14fc925c4f57
--- /dev/null
+++ b/drivers/phy/freescale/phy-fsl-imx8q-hsio.c
@@ -0,0 +1,518 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2024 NXP
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/pci_regs.h>
+#include <linux/phy/phy.h>
+#include <linux/phy/pcie.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/phy/phy-imx8-pcie.h>
+
+#define MAX_NUM_LANES	3
+#define LANE_NUM_CLKS	5
+
+/* Parameters for the waiting for PCIe PHY PLL to lock */
+#define PHY_INIT_WAIT_USLEEP_MAX	10
+#define PHY_INIT_WAIT_TIMEOUT		(1000 * PHY_INIT_WAIT_USLEEP_MAX)
+
+/* i.MX8Q HSIO registers */
+#define CTRL0			0x0
+#define APB_RSTN_0		BIT(0)
+#define APB_RSTN_1		BIT(1)
+#define PIPE_RSTN_0_MASK	GENMASK(25, 24)
+#define PIPE_RSTN_1_MASK	GENMASK(27, 26)
+#define MODE_MASK		GENMASK(20, 17)
+#define MODE_PCIE		0x0
+#define MODE_SATA		0x4
+#define DEVICE_TYPE_MASK	GENMASK(27, 24)
+#define EPCS_TXDEEMP		BIT(5)
+#define EPCS_TXDEEMP_SEL	BIT(6)
+#define EPCS_PHYRESET_N		BIT(7)
+#define RESET_N			BIT(12)
+
+#define IOB_RXENA		BIT(0)
+#define IOB_TXENA		BIT(1)
+#define IOB_A_0_TXOE		BIT(2)
+#define IOB_A_0_M1M0_2		BIT(4)
+#define IOB_A_0_M1M0_MASK	GENMASK(4, 3)
+#define PHYX1_EPCS_SEL		BIT(12)
+#define PCIE_AB_SELECT		BIT(13)
+#define CLKREQN_OUT_OVERRIDE	GENMASK(25, 24)
+
+#define PHY_STTS0		0x4
+#define LANE0_TX_PLL_LOCK	BIT(4)
+#define LANE1_TX_PLL_LOCK	BIT(12)
+
+#define CTRL2			0x8
+#define LTSSM_ENABLE		BIT(4)
+#define BUTTON_RST_N		BIT(21)
+#define PERST_N			BIT(22)
+#define POWER_UP_RST_N		BIT(23)
+
+#define PCIE_STTS0		0xc
+#define PM_REQ_CORE_RST		BIT(19)
+
+#define REG48_PMA_STATUS	0x30
+#define REG48_PMA_RDY		BIT(7)
+
+struct imx8q_hsio_drvdata {
+	int num_lane;
+};
+
+struct imx8q_hsio_lane {
+	const char * const *clk_names;
+	struct clk_bulk_data clks[LANE_NUM_CLKS];
+	u32 clks_cnt;
+	u32 ctrl_id;
+	u32 ctrl_off;
+	u32 idx;
+	u32 phy_off;
+	struct imx8q_hsio_priv *priv;
+	struct phy *phy;
+	enum phy_mode lane_mode;
+};
+
+struct imx8q_hsio_priv {
+	void __iomem *base;
+	struct device *dev;
+	u32 refclk_pad_mode;
+	u32 hsio_cfg;
+	struct regmap *phy;
+	struct regmap *ctrl;
+	struct regmap *misc;
+	const struct imx8q_hsio_drvdata *drvdata;
+	struct imx8q_hsio_lane lane[MAX_NUM_LANES];
+};
+
+static const char * const imx8q_hsio_lan0_pcie_clks[] = {"apb_pclk0", "pclk0",
+	"ctl0_crr", "phy0_crr", "misc_crr"};
+static const char * const imx8q_hsio_lan1_pciea_clks[] = {"apb_pclk1", "pclk1",
+	"ctl0_crr", "phy0_crr", "misc_crr"};
+static const char * const imx8q_hsio_lan1_pcieb_clks[] = {"apb_pclk1", "pclk1",
+	"ctl1_crr", "phy0_crr", "misc_crr"};
+static const char * const imx8q_hsio_lan2_pcieb_clks[] = {"apb_pclk2", "pclk2",
+	"ctl1_crr", "phy1_crr", "misc_crr"};
+static const char * const imx8q_hsio_lane_sata_clks[] = {"pclk2", "epcs_tx",
+	"epcs_rx", "phy1_crr", "misc_crr"};
+
+static const struct regmap_config regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+};
+
+static int imx8q_hsio_init(struct phy *phy)
+{
+	int ret, i;
+	struct imx8q_hsio_lane *lane = phy_get_drvdata(phy);
+	struct imx8q_hsio_priv *priv = lane->priv;
+	struct device *dev = priv->dev;
+
+	/* Assign clocks refer to different modes */
+	switch (lane->ctrl_id) {
+	case IMX8Q_HSIO_PCIEA_ID:
+		if (lane->idx > 1) {
+			dev_err(dev, "invalid lane ID.");
+			return -EINVAL;
+		}
+
+		lane->lane_mode = PHY_MODE_PCIE;
+		lane->ctrl_off = 0;
+		lane->phy_off = 0;
+
+		for (i = 0; i < LANE_NUM_CLKS; i++) {
+			if (lane->idx)
+				lane->clks[i].id = imx8q_hsio_lan1_pciea_clks[i];
+			else
+				lane->clks[i].id = imx8q_hsio_lan0_pcie_clks[i];
+		}
+		break;
+	case IMX8Q_HSIO_PCIEB_ID:
+		if (lane->idx > 2) {
+			dev_err(dev, "invalid lane ID.");
+			return -EINVAL;
+		}
+
+		lane->lane_mode = PHY_MODE_PCIE;
+		if (lane->idx == 0) {
+			/* i.MX8QXP */
+			lane->ctrl_off = 0;
+			lane->phy_off = 0;
+		} else {
+			/*
+			 * On i.MX8QM, only second or third lane PHY can
+			 * be binded to PCIEB.
+			 */
+			lane->ctrl_off = SZ_64K;
+			if (lane->idx == 1)
+				lane->phy_off = 0;
+			else /* idx == 2, the third lane is binded to PCIEB */
+				lane->phy_off = SZ_64K;
+		}
+
+		for (i = 0; i < LANE_NUM_CLKS; i++) {
+			if (lane->idx == 1)
+				lane->clks[i].id = imx8q_hsio_lan1_pcieb_clks[i];
+			else if (lane->idx == 2)
+				lane->clks[i].id = imx8q_hsio_lan2_pcieb_clks[i];
+			else /* i.MX8QXP only has PCIEB, it's idx == 0 */
+				lane->clks[i].id = imx8q_hsio_lan0_pcie_clks[i];
+
+		}
+		break;
+	case IMX8Q_HSIO_SATA_ID:
+		/* On i.MX8QM, only the third lane PHY can be binded to SATA */
+		if (lane->idx != 2) {
+			dev_err(dev, "invalid lane ID.");
+			return -EINVAL;
+		}
+		lane->ctrl_off = SZ_128K;
+		lane->lane_mode = PHY_MODE_SATA;
+		lane->phy_off = SZ_64K;
+
+		for (i = 0; i < LANE_NUM_CLKS; i++)
+			lane->clks[i].id = imx8q_hsio_lane_sata_clks[i];
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Fetch clocks */
+	ret = devm_clk_bulk_get(dev, LANE_NUM_CLKS, lane->clks);
+	if (ret)
+		return ret;
+
+	ret = clk_bulk_prepare_enable(LANE_NUM_CLKS, lane->clks);
+	if (ret)
+		return ret;
+
+	/* allow the clocks to stabilize */
+	usleep_range(200, 500);
+	return 0;
+}
+
+static int imx8q_hsio_exit(struct phy *phy)
+{
+	struct imx8q_hsio_lane *lane = phy_get_drvdata(phy);
+
+	clk_bulk_disable_unprepare(LANE_NUM_CLKS, lane->clks);
+
+	return 0;
+}
+
+static void imx8q_hsio_pcie_phy_resets(struct phy *phy)
+{
+	struct imx8q_hsio_lane *lane = phy_get_drvdata(phy);
+	struct imx8q_hsio_priv *priv = lane->priv;
+
+	regmap_clear_bits(priv->ctrl, lane->ctrl_off + CTRL2, BUTTON_RST_N);
+	regmap_clear_bits(priv->ctrl, lane->ctrl_off + CTRL2, PERST_N);
+	regmap_clear_bits(priv->ctrl, lane->ctrl_off + CTRL2, POWER_UP_RST_N);
+	regmap_set_bits(priv->ctrl, lane->ctrl_off + CTRL2, BUTTON_RST_N);
+	regmap_set_bits(priv->ctrl, lane->ctrl_off + CTRL2, PERST_N);
+	regmap_set_bits(priv->ctrl, lane->ctrl_off + CTRL2, POWER_UP_RST_N);
+
+	if (lane->idx == 1) {
+		/* The second lane */
+		regmap_set_bits(priv->phy, lane->phy_off + CTRL0, APB_RSTN_1);
+		regmap_set_bits(priv->phy, lane->phy_off + CTRL0, PIPE_RSTN_1_MASK);
+	} else {
+		regmap_set_bits(priv->phy, lane->phy_off + CTRL0, APB_RSTN_0);
+		regmap_set_bits(priv->phy, lane->phy_off + CTRL0, PIPE_RSTN_0_MASK);
+	}
+}
+
+static void imx8q_hsio_sata_phy_resets(struct phy *phy)
+{
+	struct imx8q_hsio_lane *lane = phy_get_drvdata(phy);
+	struct imx8q_hsio_priv *priv = lane->priv;
+
+	/* clear PHY RST, then set it */
+	regmap_clear_bits(priv->ctrl, lane->ctrl_off + CTRL0, EPCS_PHYRESET_N);
+
+	regmap_set_bits(priv->ctrl, lane->ctrl_off + CTRL0, EPCS_PHYRESET_N);
+
+	/* CTRL RST: SET -> delay 1 us -> CLEAR -> SET */
+	regmap_set_bits(priv->ctrl, lane->ctrl_off + CTRL0, RESET_N);
+	udelay(1);
+	regmap_clear_bits(priv->ctrl, lane->ctrl_off + CTRL0, RESET_N);
+	regmap_set_bits(priv->ctrl, lane->ctrl_off + CTRL0, RESET_N);
+}
+
+static void imx8q_hsio_configure_clk_pad(struct phy *phy)
+{
+	bool pll = false;
+	u32 pad_mode;
+	struct imx8q_hsio_lane *lane = phy_get_drvdata(phy);
+	struct imx8q_hsio_priv *priv = lane->priv;
+
+	pad_mode = priv->refclk_pad_mode;
+	if (pad_mode == IMX8_PCIE_REFCLK_PAD_OUTPUT) {
+		pll = true;
+		regmap_update_bits(priv->misc, CTRL0,
+				   IOB_A_0_TXOE | IOB_A_0_M1M0_MASK,
+				   IOB_A_0_TXOE | IOB_A_0_M1M0_2);
+	}
+
+	regmap_update_bits(priv->misc, CTRL0, IOB_RXENA, pll ? 0 : IOB_RXENA);
+	regmap_update_bits(priv->misc, CTRL0, IOB_TXENA, pll ? IOB_TXENA : 0);
+}
+
+static int imx8q_hsio_power_on(struct phy *phy)
+{
+	int ret;
+	u32 val, cond;
+	struct imx8q_hsio_lane *lane = phy_get_drvdata(phy);
+	struct imx8q_hsio_priv *priv = lane->priv;
+
+	if (lane->lane_mode == PHY_MODE_PCIE)
+		imx8q_hsio_pcie_phy_resets(phy);
+	else
+		/* SATA */
+		regmap_set_bits(priv->phy, lane->phy_off + CTRL0, APB_RSTN_0);
+
+	if (priv->hsio_cfg & IMX8Q_HSIO_CFG_PCIEB)
+		regmap_set_bits(priv->misc, CTRL0, PCIE_AB_SELECT);
+	if (priv->hsio_cfg & IMX8Q_HSIO_CFG_SATA)
+		regmap_set_bits(priv->misc, CTRL0, PHYX1_EPCS_SEL);
+
+	imx8q_hsio_configure_clk_pad(phy);
+
+	if (lane->lane_mode == PHY_MODE_SATA) {
+		/*
+		 * It is possible, for PCIe and SATA are sharing
+		 * the same clock source, HPLL or external oscillator.
+		 * When PCIe is in low power modes (L1.X or L2 etc),
+		 * the clock source can be turned off. In this case,
+		 * if this clock source is required to be toggling by
+		 * SATA, then SATA functions will be abnormal.
+		 * Set the override here to avoid it.
+		 */
+		regmap_set_bits(priv->misc, CTRL0, CLKREQN_OUT_OVERRIDE);
+		regmap_set_bits(priv->ctrl, lane->ctrl_off + CTRL0, EPCS_TXDEEMP);
+		regmap_set_bits(priv->ctrl, lane->ctrl_off + CTRL0, EPCS_TXDEEMP_SEL);
+
+		imx8q_hsio_sata_phy_resets(phy);
+	} else {
+		/* Toggle apb_pclk to make sure clear the PM_REQ_CORE_RST bit */
+		clk_disable_unprepare(lane->clks[0].clk);
+		mdelay(1);
+		ret = clk_prepare_enable(lane->clks[0].clk);
+		if (ret) {
+			dev_err(priv->dev, "unable to enable phy apb_pclk\n");
+			return ret;
+		}
+
+		/* Bit19 PM_REQ_CORE_RST of pcie_stts0 should be cleared. */
+		ret = regmap_read_poll_timeout(priv->ctrl,
+				lane->ctrl_off + PCIE_STTS0,
+				val, (val & PM_REQ_CORE_RST) == 0,
+				PHY_INIT_WAIT_USLEEP_MAX,
+				PHY_INIT_WAIT_TIMEOUT);
+		if (ret) {
+			dev_err(priv->dev, "PM_REQ_CORE_RST is set\n");
+			return ret;
+		}
+	}
+
+	/* Polling to check the PHY is ready or not. */
+	if (lane->idx == 1)
+		cond = LANE1_TX_PLL_LOCK;
+	else
+		cond = LANE0_TX_PLL_LOCK;
+
+	ret = regmap_read_poll_timeout(priv->phy, lane->phy_off + PHY_STTS0,
+			val, ((val & cond) == cond),
+			PHY_INIT_WAIT_USLEEP_MAX, PHY_INIT_WAIT_TIMEOUT);
+	if (ret)
+		dev_err(priv->dev, "IMX8Q PHY%d PLL lock timeout\n", lane->idx);
+	else
+		dev_info(priv->dev, "IMX8Q PHY%d PLL is locked\n", lane->idx);
+
+	if (lane->lane_mode == PHY_MODE_SATA) {
+		cond = REG48_PMA_RDY;
+		ret = read_poll_timeout(readb, val, ((val & cond) == cond),
+				PHY_INIT_WAIT_USLEEP_MAX, PHY_INIT_WAIT_TIMEOUT,
+				false, priv->base + REG48_PMA_STATUS);
+		if (ret)
+			dev_err(priv->dev, "PHY calibration is timeout\n");
+		else
+			dev_info(priv->dev, "PHY calibration is done\n");
+	}
+
+	return ret;
+}
+
+static int imx8q_hsio_set_mode(struct phy *phy, enum phy_mode mode,
+				   int submode)
+{
+	u32 val;
+	struct imx8q_hsio_lane *lane = phy_get_drvdata(phy);
+	struct imx8q_hsio_priv *priv = lane->priv;
+
+	if (lane->lane_mode != mode)
+		return -EINVAL;
+
+	val = (mode == PHY_MODE_PCIE) ? MODE_PCIE : MODE_SATA;
+	val = FIELD_PREP(MODE_MASK, val);
+	regmap_update_bits(priv->phy, lane->phy_off + CTRL0, MODE_MASK, val);
+
+	switch (submode) {
+	case PHY_MODE_PCIE_RC:
+		val = FIELD_PREP(DEVICE_TYPE_MASK, PCI_EXP_TYPE_ROOT_PORT);
+		break;
+	case PHY_MODE_PCIE_EP:
+		val = FIELD_PREP(DEVICE_TYPE_MASK, PCI_EXP_TYPE_ENDPOINT);
+		break;
+	default: /* Support only PCIe EP and RC now. */
+		return 0;
+	}
+	if (submode)
+		regmap_update_bits(priv->ctrl, lane->ctrl_off + CTRL0,
+				   DEVICE_TYPE_MASK, val);
+
+	return 0;
+}
+
+static int imx8q_hsio_set_speed(struct phy *phy, int speed)
+{
+	struct imx8q_hsio_lane *lane = phy_get_drvdata(phy);
+	struct imx8q_hsio_priv *priv = lane->priv;
+
+	regmap_update_bits(priv->ctrl, lane->ctrl_off + CTRL2, LTSSM_ENABLE,
+			   speed ? LTSSM_ENABLE : 0);
+	return 0;
+}
+
+static const struct phy_ops imx8q_hsio_ops = {
+	.init = imx8q_hsio_init,
+	.exit = imx8q_hsio_exit,
+	.power_on = imx8q_hsio_power_on,
+	.set_mode = imx8q_hsio_set_mode,
+	.set_speed = imx8q_hsio_set_speed,
+	.owner = THIS_MODULE,
+};
+
+static const struct imx8q_hsio_drvdata imx8qxp_serdes_drvdata = {
+	.num_lane = 1,
+};
+
+static const struct imx8q_hsio_drvdata imx8qm_serdes_drvdata = {
+	.num_lane = 3,
+};
+
+static const struct of_device_id imx8q_hsio_of_match[] = {
+	{.compatible = "fsl,imx8qxp-serdes", .data = &imx8qxp_serdes_drvdata},
+	{.compatible = "fsl,imx8qm-serdes", .data = &imx8qm_serdes_drvdata},
+	{ },
+};
+
+MODULE_DEVICE_TABLE(of, imx8q_hsio_of_match);
+
+static struct phy *imx8q_hsio_xlate(struct device *dev,
+				    const struct of_phandle_args *args)
+{
+	struct imx8q_hsio_priv *priv = dev_get_drvdata(dev);
+	int idx = args->args[0];
+	int ctrl_id = args->args[1];
+	int hsio_cfg = args->args[2];
+
+	if (idx >= priv->drvdata->num_lane)
+		return ERR_PTR(-EINVAL);
+	priv->lane[idx].idx = idx;
+	priv->lane[idx].ctrl_id = ctrl_id;
+	priv->hsio_cfg = hsio_cfg;
+
+	return priv->lane[idx].phy;
+}
+
+static int imx8q_hsio_probe(struct platform_device *pdev)
+{
+	int i;
+	void __iomem *off;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	const struct of_device_id *of_id;
+	struct imx8q_hsio_priv *priv;
+	struct phy_provider *provider;
+
+	of_id = of_match_device(imx8q_hsio_of_match, dev);
+	if (!of_id)
+		return -EINVAL;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	priv->dev = &pdev->dev;
+	priv->drvdata = of_device_get_match_data(dev);
+
+	/* Get PHY refclk pad mode */
+	of_property_read_u32(np, "fsl,refclk-pad-mode", &priv->refclk_pad_mode);
+
+	priv->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	off = devm_platform_ioremap_resource_byname(pdev, "phy");
+	priv->phy = devm_regmap_init_mmio(dev, off, &regmap_config);
+	if (IS_ERR(priv->phy))
+		return dev_err_probe(dev, PTR_ERR(priv->phy),
+				     "unable to find phy csr registers\n");
+
+	off = devm_platform_ioremap_resource_byname(pdev, "ctrl");
+	priv->ctrl = devm_regmap_init_mmio(dev, off, &regmap_config);
+	if (IS_ERR(priv->ctrl))
+		return dev_err_probe(dev, PTR_ERR(priv->ctrl),
+				     "unable to find ctrl csr registers\n");
+
+	off = devm_platform_ioremap_resource_byname(pdev, "misc");
+	priv->misc = devm_regmap_init_mmio(dev, off, &regmap_config);
+	if (IS_ERR(priv->misc))
+		return dev_err_probe(dev, PTR_ERR(priv->misc),
+				     "unable to find misc csr registers\n");
+
+	for (i = 0; i < priv->drvdata->num_lane; i++) {
+		struct imx8q_hsio_lane *lane = &priv->lane[i];
+		struct phy *phy;
+
+		memset(lane, 0, sizeof(*lane));
+
+		phy = devm_phy_create(&pdev->dev, NULL, &imx8q_hsio_ops);
+		if (IS_ERR(phy))
+			return PTR_ERR(phy);
+
+		lane->priv = priv;
+		lane->phy = phy;
+		lane->idx = i;
+		phy_set_drvdata(phy, lane);
+	}
+
+	dev_set_drvdata(dev, priv);
+	dev_set_drvdata(&pdev->dev, priv);
+
+	provider = devm_of_phy_provider_register(&pdev->dev, imx8q_hsio_xlate);
+
+	return PTR_ERR_OR_ZERO(provider);
+}
+
+static struct platform_driver imx8q_hsio_driver = {
+	.probe	= imx8q_hsio_probe,
+	.driver = {
+		.name	= "imx8q-hsio-phy",
+		.of_match_table	= imx8q_hsio_of_match,
+	}
+};
+module_platform_driver(imx8q_hsio_driver);
+
+MODULE_DESCRIPTION("FSL IMX8Q HSIO SERDES PHY driver");
+MODULE_LICENSE("GPL");
-- 
2.37.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v1 2/3] dt-bindings: phy: phy-imx8-pcie: Add binding for i.MX8Q HSIO SerDes PHY
From: Richard Zhu @ 2024-03-29  8:09 UTC (permalink / raw)
  To: vkoul, kishon, robh+dt, krzysztof.kozlowski+dt, conor+dt,
	frank.li
  Cc: hongxing.zhu, linux-phy, devicetree, linux-arm-kernel,
	linux-kernel, kernel, linux-imx
In-Reply-To: <1711699790-16494-1-git-send-email-hongxing.zhu@nxp.com>

Add binding for controller ID and HSIO configuration setting of the
i.MX8Q HSIO SerDes PHY.

Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
---
 include/dt-bindings/phy/phy-imx8-pcie.h | 26 +++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/include/dt-bindings/phy/phy-imx8-pcie.h b/include/dt-bindings/phy/phy-imx8-pcie.h
index 8bbe2d6538d8..5cd5580879fa 100644
--- a/include/dt-bindings/phy/phy-imx8-pcie.h
+++ b/include/dt-bindings/phy/phy-imx8-pcie.h
@@ -11,4 +11,30 @@
 #define IMX8_PCIE_REFCLK_PAD_INPUT	1
 #define IMX8_PCIE_REFCLK_PAD_OUTPUT	2
 
+/*
+ * i.MX8QM HSIO subsystem has three lane PHYs and three controllers:
+ * PCIEA(2 lanes capapble PCIe controller), PCIEB (only support one
+ * lane) and SATA.
+ * In the different use cases. PCIEA can be binded to PHY lane0, lane1
+ * or Lane0 and lane1. PCIEB can be binded to lane1 or lane2 PHY. SATA
+ * can only be binded to last lane2 PHY.
+ * Define i.MX8Q HSIO controller ID here to specify the controller
+ * binded to the PHY.
+ * Meanwhile, i.MX8QXP HSIO subsystem has one lane PHY and PCIEB(only
+ * support one lane) controller.
+ */
+#define IMX8Q_HSIO_PCIEA_ID	0
+#define IMX8Q_HSIO_PCIEB_ID	1
+#define IMX8Q_HSIO_SATA_ID	2
+
+/*
+ * On i.MX8QM, PCIEA is mandatory required if the HSIO is enabled.
+ * Define configurations beside PCIEA is enabled.
+ * On i.MX8QXP, HSIO module only has PCIEB and one lane PHY.
+ * The "IMX8Q_HSIO_CFG_PCIEB" can be used on i.MX8QXP platforms.
+ */
+#define IMX8Q_HSIO_CFG_SATA		1
+#define IMX8Q_HSIO_CFG_PCIEB		2
+#define IMX8Q_HSIO_CFG_PCIEBSATA	3
+
 #endif /* _DT_BINDINGS_IMX8_PCIE_H */
-- 
2.37.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* Re: [PATCH v11 00/11] Support page table check PowerPC
From: Christophe Leroy @ 2024-03-29  8:29 UTC (permalink / raw)
  To: Rohan McLure, linuxppc-dev@lists.ozlabs.org
  Cc: mpe@ellerman.id.au, linux-mm@kvack.org,
	linux-riscv@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org, x86@kernel.org
In-Reply-To: <eb906bc3-b372-449b-a351-eb739ffa7418@csgroup.eu>



Le 28/03/2024 à 08:57, Christophe Leroy a écrit :
> 
> 
> Le 28/03/2024 à 07:52, Christophe Leroy a écrit :
>>
>>
>> Le 28/03/2024 à 05:55, Rohan McLure a écrit :
>>> Support page table check on all PowerPC platforms. This works by
>>> serialising assignments, reassignments and clears of page table
>>> entries at each level in order to ensure that anonymous mappings
>>> have at most one writable consumer, and likewise that file-backed
>>> mappings are not simultaneously also anonymous mappings.
>>>
>>> In order to support this infrastructure, a number of stubs must be
>>> defined for all powerpc platforms. Additionally, seperate set_pte_at()
>>> and set_pte_at_unchecked(), to allow for internal, uninstrumented 
>>> mappings.
>>
>> I gave it a try on QEMU e500 (64 bits), and get the following Oops. 
>> What do I have to look for ?
>>
>> Freeing unused kernel image (initmem) memory: 2588K
>> This architecture does not have kernel memory protection.
>> Run /init as init process
>> ------------[ cut here ]------------
>> kernel BUG at mm/page_table_check.c:119!
>> Oops: Exception in kernel mode, sig: 5 [#1]
>> BE PAGE_SIZE=4K SMP NR_CPUS=32 QEMU e500
> 
> Same problem on my 8xx board:
> 
> [    7.358146] Freeing unused kernel image (initmem) memory: 448K
> [    7.363957] Run /init as init process
> [    7.370955] ------------[ cut here ]------------
> [    7.375411] kernel BUG at mm/page_table_check.c:119!
> [    7.380393] Oops: Exception in kernel mode, sig: 5 [#1]
> [    7.385621] BE PAGE_SIZE=16K PREEMPT CMPC885

Both problems are fixed by following change:

diff --git a/arch/powerpc/include/asm/nohash/pgtable.h 
b/arch/powerpc/include/asm/nohash/pgtable.h
index 413d01a51e6f..5b932632a5d7 100644
--- a/arch/powerpc/include/asm/nohash/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/pgtable.h
@@ -29,6 +29,8 @@ static inline pte_basic_t pte_update(struct mm_struct 
*mm, unsigned long addr, p

  #ifndef __ASSEMBLY__

+#include <linux/page_table_check.h>
+
  extern int icache_44x_need_flush;

  /*
@@ -92,7 +94,11 @@ static inline void ptep_set_wrprotect(struct 
mm_struct *mm, unsigned long addr,
  static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned 
long addr,
  				       pte_t *ptep)
  {
-	return __pte(pte_update(mm, addr, ptep, ~0UL, 0, 0));
+	pte_t old_pte = __pte(pte_update(mm, addr, ptep, ~0UL, 0, 0));
+
+	page_table_check_pte_clear(mm, addr, old_pte);
+
+	return old_pte;
  }
  #define __HAVE_ARCH_PTEP_GET_AND_CLEAR


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox