From 71451b7105c777429de9bd3961666f02edd4f40e Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 1 Apr 2026 10:27:57 +0200 Subject: [PATCH 01/30] arch/mips: Drop CONFIG_FIRMWARE_EDID from defconfig files CONFIG_FIRMWARE_EDID=y depends on X86 or EFI_GENERIC_STUB. Neither is true here, so drop the lines from the defconfig files. Signed-off-by: Thomas Zimmermann Signed-off-by: Thomas Bogendoerfer --- arch/mips/configs/ip32_defconfig | 1 - arch/mips/configs/lemote2f_defconfig | 1 - arch/mips/configs/malta_qemu_32r6_defconfig | 1 - arch/mips/configs/maltaaprp_defconfig | 1 - arch/mips/configs/maltasmvp_defconfig | 1 - arch/mips/configs/maltasmvp_eva_defconfig | 1 - arch/mips/configs/maltaup_defconfig | 1 - 7 files changed, 7 deletions(-) diff --git a/arch/mips/configs/ip32_defconfig b/arch/mips/configs/ip32_defconfig index 7568838eb08b..ad60c11dd660 100644 --- a/arch/mips/configs/ip32_defconfig +++ b/arch/mips/configs/ip32_defconfig @@ -71,7 +71,6 @@ CONFIG_SERIAL_8250_CONSOLE=y CONFIG_HW_RANDOM=y CONFIG_WATCHDOG=y CONFIG_FB=y -CONFIG_FIRMWARE_EDID=y CONFIG_FB_GBE=y # CONFIG_VGA_CONSOLE is not set CONFIG_FRAMEBUFFER_CONSOLE=y diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig index 8d3f20ed19b5..7eed322a986f 100644 --- a/arch/mips/configs/lemote2f_defconfig +++ b/arch/mips/configs/lemote2f_defconfig @@ -136,7 +136,6 @@ CONFIG_FB_SIS_300=y CONFIG_FB_SIS_315=y CONFIG_FB_SIMPLE=y CONFIG_FB_SM712=y -CONFIG_FIRMWARE_EDID=y CONFIG_FB_MODE_HELPERS=y CONFIG_FB_TILEBLITTING=y CONFIG_BACKLIGHT_CLASS_DEVICE=y diff --git a/arch/mips/configs/malta_qemu_32r6_defconfig b/arch/mips/configs/malta_qemu_32r6_defconfig index accb471a1d93..4bc5ea492a94 100644 --- a/arch/mips/configs/malta_qemu_32r6_defconfig +++ b/arch/mips/configs/malta_qemu_32r6_defconfig @@ -129,7 +129,6 @@ CONFIG_POWER_RESET_PIIX4_POWEROFF=y CONFIG_POWER_RESET_SYSCON=y # CONFIG_HWMON is not set CONFIG_FB=y -CONFIG_FIRMWARE_EDID=y CONFIG_FB_MATROX=y CONFIG_FB_MATROX_G=y CONFIG_USB=y diff --git a/arch/mips/configs/maltaaprp_defconfig b/arch/mips/configs/maltaaprp_defconfig index 6bda67c5f68f..3fc0bfff9795 100644 --- a/arch/mips/configs/maltaaprp_defconfig +++ b/arch/mips/configs/maltaaprp_defconfig @@ -130,7 +130,6 @@ CONFIG_POWER_RESET_PIIX4_POWEROFF=y CONFIG_POWER_RESET_SYSCON=y # CONFIG_HWMON is not set CONFIG_FB=y -CONFIG_FIRMWARE_EDID=y CONFIG_FB_MATROX=y CONFIG_FB_MATROX_G=y CONFIG_USB=y diff --git a/arch/mips/configs/maltasmvp_defconfig b/arch/mips/configs/maltasmvp_defconfig index e4082537f80f..eefaa45defb5 100644 --- a/arch/mips/configs/maltasmvp_defconfig +++ b/arch/mips/configs/maltasmvp_defconfig @@ -130,7 +130,6 @@ CONFIG_POWER_RESET_PIIX4_POWEROFF=y CONFIG_POWER_RESET_SYSCON=y # CONFIG_HWMON is not set CONFIG_FB=y -CONFIG_FIRMWARE_EDID=y CONFIG_FB_MATROX=y CONFIG_FB_MATROX_G=y CONFIG_USB=y diff --git a/arch/mips/configs/maltasmvp_eva_defconfig b/arch/mips/configs/maltasmvp_eva_defconfig index 58f5af45fa98..691356ef2983 100644 --- a/arch/mips/configs/maltasmvp_eva_defconfig +++ b/arch/mips/configs/maltasmvp_eva_defconfig @@ -133,7 +133,6 @@ CONFIG_POWER_RESET_PIIX4_POWEROFF=y CONFIG_POWER_RESET_SYSCON=y # CONFIG_HWMON is not set CONFIG_FB=y -CONFIG_FIRMWARE_EDID=y CONFIG_FB_MATROX=y CONFIG_FB_MATROX_G=y CONFIG_USB=y diff --git a/arch/mips/configs/maltaup_defconfig b/arch/mips/configs/maltaup_defconfig index 9bfef7de0d1c..0d02e26ef6f5 100644 --- a/arch/mips/configs/maltaup_defconfig +++ b/arch/mips/configs/maltaup_defconfig @@ -129,7 +129,6 @@ CONFIG_POWER_RESET_PIIX4_POWEROFF=y CONFIG_POWER_RESET_SYSCON=y # CONFIG_HWMON is not set CONFIG_FB=y -CONFIG_FIRMWARE_EDID=y CONFIG_FB_MATROX=y CONFIG_FB_MATROX_G=y CONFIG_USB=y From a163a96d4afb29c0783b4a3a26ff64440713f514 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Sat, 28 Mar 2026 14:29:10 +0000 Subject: [PATCH 02/30] MIPS: kernel: Remove $0 clobber from `mult_sh_align_mod' Remove rubbish $0 clobber added to inline asm within `mult_sh_align_mod' with the removal of support for GCC versions below 3.4 made with commit 57810ecb581a ("MIPS: Remove GCC_IMM_ASM & GCC_REG_ACCUM macros"). Previously a macro was used that, depending on GCC version, expanded to either `accum' or $0. Since the latter choice was only a placeholder to keep the syntax consistent and the register referred is hardwired, there is no point in having it here as it has no effect on code generation. Signed-off-by: Maciej W. Rozycki Signed-off-by: Thomas Bogendoerfer --- arch/mips/kernel/r4k-bugs64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/kernel/r4k-bugs64.c b/arch/mips/kernel/r4k-bugs64.c index 1e300330078d..83970ac7e901 100644 --- a/arch/mips/kernel/r4k-bugs64.c +++ b/arch/mips/kernel/r4k-bugs64.c @@ -91,7 +91,7 @@ void mult_sh_align_mod(long *v1, long *v2, long *w, ".set pop" : "=&r" (lv1), "=r" (lw) : "r" (m1), "r" (m2), "r" (s), "I" (0) - : "hi", "lo", "$0"); + : "hi", "lo"); /* We have to use single integers for m1 and m2 and a double * one for p to be sure the mulsidi3 gcc's RTL multiplication * instruction has the workaround applied. Older versions of From 56236b7f6f4461e2aa1d1210de14e91c61601e53 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Sat, 28 Mar 2026 15:49:57 +0000 Subject: [PATCH 03/30] MIPS: DEC: Rate-limit memory errors for ECC systems Prevent the system from becoming unusable due to a flood of memory error messages with DECstation and DECsystem models using ECC, that is KN02, KN03 and KN05 systems. It seems common for gradual oxidation of memory module contacts to cause memory errors to eventually develop and while ECC takes care of correcting them and the system affected can continue operating normally until the contacts have been cleaned, the unlimited messages make the system spend all its time on producing them, therefore preventing it from being used. Rate-limiting removes the load from the system and enables its normal operation, e.g.: Bus error interrupt: CPU memory read ECC error at 0x139cfb04 ECC syndrome 0x54 -- corrected single bit error at data bit D3 Bus error interrupt: CPU partial memory write ECC error at 0x138c1f5c ECC syndrome 0x54 -- corrected single bit error at data bit D3 Bus error interrupt: CPU partial memory write ECC error at 0x138c1f6c ECC syndrome 0x54 -- corrected single bit error at data bit D3 Bus error interrupt: CPU memory read ECC error at 0x139cff64 ECC syndrome 0x54 -- corrected single bit error at data bit D3 Bus error interrupt: CPU memory read ECC error at 0x136af00c ECC syndrome 0x54 -- corrected single bit error at data bit D3 Bus error interrupt: CPU memory read ECC error at 0x136af044 ECC syndrome 0x54 -- corrected single bit error at data bit D3 Bus error interrupt: CPU memory read ECC error at 0x136af0cc ECC syndrome 0x54 -- corrected single bit error at data bit D3 Bus error interrupt: CPU memory read ECC error at 0x136af0cc ECC syndrome 0x54 -- corrected single bit error at data bit D3 Bus error interrupt: CPU memory read ECC error at 0x136af0e4 ECC syndrome 0x54 -- corrected single bit error at data bit D3 Bus error interrupt: CPU memory read ECC error at 0x136af104 ECC syndrome 0x54 -- corrected single bit error at data bit D3 dec_ecc_be_backend: 34455 callbacks suppressed Signed-off-by: Maciej W. Rozycki Signed-off-by: Thomas Bogendoerfer --- arch/mips/dec/ecc-berr.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/arch/mips/dec/ecc-berr.c b/arch/mips/dec/ecc-berr.c index 1eb356fdd832..3d41ff07d817 100644 --- a/arch/mips/dec/ecc-berr.c +++ b/arch/mips/dec/ecc-berr.c @@ -5,12 +5,13 @@ * 5000/240 (KN03), 5000/260 (KN05) and DECsystem 5900 (KN03), * 5900/260 (KN05) systems. * - * Copyright (c) 2003, 2005 Maciej W. Rozycki + * Copyright (c) 2003, 2005, 2026 Maciej W. Rozycki */ #include #include #include +#include #include #include @@ -51,6 +52,10 @@ static int dec_ecc_be_backend(struct pt_regs *regs, int is_fixup, int invoker) static const char overstr[] = "overrun"; static const char eccstr[] = "ECC error"; + static DEFINE_RATELIMIT_STATE(rs, + DEFAULT_RATELIMIT_INTERVAL, + DEFAULT_RATELIMIT_BURST); + const char *kind, *agent, *cycle, *event; const char *status = "", *xbit = "", *fmt = ""; unsigned long address; @@ -70,7 +75,7 @@ static int dec_ecc_be_backend(struct pt_regs *regs, int is_fixup, int invoker) if (!(erraddr & KN0X_EAR_VALID)) { /* No idea what happened. */ - printk(KERN_ALERT "Unidentified bus error %s\n", kind); + pr_alert_ratelimited("Unidentified bus error %s\n", kind); return action; } @@ -180,12 +185,13 @@ static int dec_ecc_be_backend(struct pt_regs *regs, int is_fixup, int invoker) } } - if (action != MIPS_BE_FIXUP) + if (action != MIPS_BE_FIXUP && __ratelimit(&rs)) { printk(KERN_ALERT "Bus error %s: %s %s %s at %#010lx\n", kind, agent, cycle, event, address); - if (action != MIPS_BE_FIXUP && erraddr & KN0X_EAR_ECCERR) - printk(fmt, " ECC syndrome ", syn, status, xbit, i); + if (erraddr & KN0X_EAR_ECCERR) + printk(fmt, " ECC syndrome ", syn, status, xbit, i); + } return action; } From 798715fa06e1b3ff0f672721cca0a6789d5ebd37 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Sat, 28 Mar 2026 15:50:01 +0000 Subject: [PATCH 04/30] MIPS: DEC: Rate-limit memory errors for KN01 systems Similarly to memory errors in ECC systems also rate-limit memory parity errors for KN01 DECstation and DECsystem models. Unlike with ECC these events are always fatal and are less likely to cause a message flood, but handle them the same way for consistency. Signed-off-by: Maciej W. Rozycki Signed-off-by: Thomas Bogendoerfer --- arch/mips/dec/kn01-berr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/mips/dec/kn01-berr.c b/arch/mips/dec/kn01-berr.c index 76efed7bc9f3..27addf7f31c7 100644 --- a/arch/mips/dec/kn01-berr.c +++ b/arch/mips/dec/kn01-berr.c @@ -4,7 +4,7 @@ * and 2100 (KN01) systems equipped with parity error detection * logic. * - * Copyright (c) 2005 Maciej W. Rozycki + * Copyright (c) 2005, 2026 Maciej W. Rozycki */ #include @@ -134,8 +134,8 @@ static int dec_kn01_be_backend(struct pt_regs *regs, int is_fixup, int invoker) action = MIPS_BE_FIXUP; if (action != MIPS_BE_FIXUP) - printk(KERN_ALERT "Bus error %s: %s %s %s at %#010lx\n", - kind, agent, cycle, event, address); + pr_alert_ratelimited("Bus error %s: %s %s %s at %#010lx\n", + kind, agent, cycle, event, address); return action; } From c523378ce6f65298fc1cb6be7c0e59a9008be446 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Sat, 28 Mar 2026 15:50:05 +0000 Subject: [PATCH 05/30] MIPS: DEC: Rate-limit memory errors for non-KN01 parity systems Similarly to memory errors in ECC systems also rate-limit memory parity errors for KN02-BA, KN02-CA, KN04-BA, KN04-CA DECstation and DECsystem models. Unlike with ECC these events are always fatal and are less likely to cause a message flood, but handle them the same way for consistency. Signed-off-by: Maciej W. Rozycki Signed-off-by: Thomas Bogendoerfer --- arch/mips/dec/kn02xa-berr.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/arch/mips/dec/kn02xa-berr.c b/arch/mips/dec/kn02xa-berr.c index 9699fc4e6eb1..6e494db1e437 100644 --- a/arch/mips/dec/kn02xa-berr.c +++ b/arch/mips/dec/kn02xa-berr.c @@ -6,12 +6,13 @@ * DECstation/DECsystem 5000/20, /25, /33 (KN02-CA), 5000/50 * (KN04-CA) systems. * - * Copyright (c) 2005 Maciej W. Rozycki + * Copyright (c) 2005, 2026 Maciej W. Rozycki */ #include #include #include +#include #include #include @@ -50,6 +51,10 @@ static int dec_kn02xa_be_backend(struct pt_regs *regs, int is_fixup, static const char paritystr[] = "parity error"; static const char lanestat[][4] = { " OK", "BAD" }; + static DEFINE_RATELIMIT_STATE(rs, + DEFAULT_RATELIMIT_INTERVAL, + DEFAULT_RATELIMIT_BURST); + const char *kind, *agent, *cycle, *event; unsigned long address; @@ -79,18 +84,19 @@ static int dec_kn02xa_be_backend(struct pt_regs *regs, int is_fixup, if (is_fixup) action = MIPS_BE_FIXUP; - if (action != MIPS_BE_FIXUP) + if (action != MIPS_BE_FIXUP && __ratelimit(&rs)) { printk(KERN_ALERT "Bus error %s: %s %s %s at %#010lx\n", kind, agent, cycle, event, address); - if (action != MIPS_BE_FIXUP && address < 0x10000000) - printk(KERN_ALERT " Byte lane status %#3x -- " - "#3: %s, #2: %s, #1: %s, #0: %s\n", - (mer & KN02XA_MER_BYTERR) >> 8, - lanestat[(mer & KN02XA_MER_BYTERR_3) != 0], - lanestat[(mer & KN02XA_MER_BYTERR_2) != 0], - lanestat[(mer & KN02XA_MER_BYTERR_1) != 0], - lanestat[(mer & KN02XA_MER_BYTERR_0) != 0]); + if (address < 0x10000000) + printk(KERN_ALERT " Byte lane status %#3x -- " + "#3: %s, #2: %s, #1: %s, #0: %s\n", + (mer & KN02XA_MER_BYTERR) >> 8, + lanestat[(mer & KN02XA_MER_BYTERR_3) != 0], + lanestat[(mer & KN02XA_MER_BYTERR_2) != 0], + lanestat[(mer & KN02XA_MER_BYTERR_1) != 0], + lanestat[(mer & KN02XA_MER_BYTERR_0) != 0]); + } return action; } From 7d1b6b70927e0b65e2768c3f625f9da60635efad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Lebrun?= Date: Wed, 25 Feb 2026 17:55:22 +0100 Subject: [PATCH 06/30] dt-bindings: soc: mobileye: OLB is an Ethernet PHY provider on EyeQ5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OLB on EyeQ5 ("mobileye,eyeq5-olb" compatible) is now declared as a generic PHY provider. Under the hood, it provides Ethernet RGMII/SGMII PHY support for both MAC instances. Acked-by: Conor Dooley Signed-off-by: Théo Lebrun Signed-off-by: Thomas Bogendoerfer --- .../bindings/soc/mobileye/mobileye,eyeq5-olb.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml index 6d11472ba5a7..56401d76a9b5 100644 --- a/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml +++ b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml @@ -51,6 +51,9 @@ properties: clock-names: const: ref + '#phy-cells': + const: 1 + patternProperties: '-pins?$': type: object @@ -310,7 +313,7 @@ allOf: properties: '#reset-cells': false - # Only EyeQ5 has pinctrl in OLB. + # Only EyeQ5 has pinctrl and PHY in OLB. - if: not: properties: @@ -320,6 +323,8 @@ allOf: then: patternProperties: '-pins?$': false + properties: + '#phy-cells': false examples: - | From a692761a8e7b0c1abce92af476972357765f69c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Lebrun?= Date: Wed, 25 Feb 2026 17:55:23 +0100 Subject: [PATCH 07/30] MIPS: mobileye: eyeq5: add two Cadence GEM Ethernet controllers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add both MACB/GEM instances found in the Mobileye EyeQ5 SoC. Acked-by: Thomas Bogendoerfer Signed-off-by: Théo Lebrun Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/mobileye/eyeq5.dtsi | 45 ++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/arch/mips/boot/dts/mobileye/eyeq5.dtsi b/arch/mips/boot/dts/mobileye/eyeq5.dtsi index 36a73e8a63a1..cec5ad875228 100644 --- a/arch/mips/boot/dts/mobileye/eyeq5.dtsi +++ b/arch/mips/boot/dts/mobileye/eyeq5.dtsi @@ -77,6 +77,8 @@ aliases { serial0 = &uart0; serial1 = &uart1; serial2 = &uart2; + ethernet0 = &macb0; + ethernet1 = &macb1; }; cpu_intc: interrupt-controller { @@ -231,6 +233,7 @@ olb: system-controller@e00000 { #clock-cells = <1>; clocks = <&xtal>; clock-names = "ref"; + #phy-cells = <1>; }; gic: interrupt-controller@140000 { @@ -305,6 +308,48 @@ gpio1: gpio@1500000 { #interrupt-cells = <2>; resets = <&olb 0 26>; }; + + iocu-bus { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + dma-coherent; + dma-ranges = <0x10 0x00000000 0x0 0x0 0x10 0>; + + macb0: ethernet@2a00000 { + compatible = "mobileye,eyeq5-gem"; + reg = <0x0 0x02a00000 0x0 0x4000>; + interrupt-parent = <&gic>; + /* One interrupt per queue */ + interrupts = , + , + , + ; + clock-names = "pclk", "hclk", "tsu_clk"; + clocks = <&pclk>, <&pclk>, <&tsu_clk>; + nvmem-cells = <ð0_mac>; + nvmem-cell-names = "mac-address"; + phys = <&olb 0>; + }; + + macb1: ethernet@2b00000 { + compatible = "mobileye,eyeq5-gem"; + reg = <0x0 0x02b00000 0x0 0x4000>; + interrupt-parent = <&gic>; + /* One interrupt per queue */ + interrupts = , + , + , + ; + clock-names = "pclk", "hclk", "tsu_clk"; + clocks = <&pclk>, <&pclk>, <&tsu_clk>; + nvmem-cells = <ð1_mac>; + nvmem-cell-names = "mac-address"; + phys = <&olb 1>; + }; + }; + }; }; From ff8efe28bb3a184422c71553675385625c710c10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Lebrun?= Date: Wed, 25 Feb 2026 17:55:24 +0100 Subject: [PATCH 08/30] MIPS: mobileye: eyeq5-epm: add two Cadence GEM Ethernet PHYs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Mobileye EyeQ5 eval board (EPM) embeds two MDIO PHYs. Reviewed-by: Andrew Lunn Acked-by: Thomas Bogendoerfer Signed-off-by: Théo Lebrun Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/mobileye/eyeq5-epm5.dts | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/arch/mips/boot/dts/mobileye/eyeq5-epm5.dts b/arch/mips/boot/dts/mobileye/eyeq5-epm5.dts index 9fc1a1b0a81b..babf52731ea6 100644 --- a/arch/mips/boot/dts/mobileye/eyeq5-epm5.dts +++ b/arch/mips/boot/dts/mobileye/eyeq5-epm5.dts @@ -29,3 +29,29 @@ temperature-sensor@48 { label = "U60"; }; }; + +&macb0 { + phy-mode = "sgmii"; + phy-handle = <&macb0_phy>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + macb0_phy: ethernet-phy@e { + reg = <0xe>; + }; + }; +}; + +&macb1 { + phy-mode = "rgmii-id"; + phy-handle = <&macb1_phy>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + macb1_phy: ethernet-phy@e { + reg = <0xe>; + }; + }; +}; From c7dd395d7b53a66de8503507fe7ef21b8fab3e57 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Mon, 9 Mar 2026 13:18:18 +0000 Subject: [PATCH 09/30] mips: dts: Add PCIe to EcoNet EN751221 Add PCIe based on EN7528 PCIe driver, also add two MT76 wifi devices to SmartFiber XP8421-B. Signed-off-by: Caleb James DeLisle Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/econet/en751221.dtsi | 114 ++++++++++++++++++ .../econet/en751221_smartfiber_xp8421-b.dts | 21 ++++ arch/mips/econet/Kconfig | 2 + 3 files changed, 137 insertions(+) diff --git a/arch/mips/boot/dts/econet/en751221.dtsi b/arch/mips/boot/dts/econet/en751221.dtsi index 2abeef5b744a..72cb65654c34 100644 --- a/arch/mips/boot/dts/econet/en751221.dtsi +++ b/arch/mips/boot/dts/econet/en751221.dtsi @@ -1,6 +1,8 @@ // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) /dts-v1/; +#include + / { compatible = "econet,en751221"; #address-cells = <1>; @@ -30,6 +32,30 @@ cpuintc: interrupt-controller { #interrupt-cells = <1>; }; + chip_scu: syscon@1fa20000 { + compatible = "econet,en751221-chip-scu", "syscon"; + reg = <0x1fa20000 0x388>; + }; + + pcie_phy1: pcie-phy@1fac0000 { + compatible = "econet,en751221-pcie-gen2"; + reg = <0x1fac0000 0x1000>; + #phy-cells = <0>; + }; + + pcie_phy0: pcie-phy@1faf2000 { + compatible = "econet,en751221-pcie-gen1"; + reg = <0x1faf2000 0x1000>; + #phy-cells = <0>; + }; + + scuclk: clock-controller@1fb00000 { + compatible = "econet,en751221-scu"; + reg = <0x1fb00000 0x970>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + intc: interrupt-controller@1fb40000 { compatible = "econet,en751221-intc"; reg = <0x1fb40000 0x100>; @@ -41,6 +67,94 @@ intc: interrupt-controller@1fb40000 { econet,shadow-interrupts = <7 2>, <8 3>, <13 12>, <30 29>; }; + pciecfg: pciecfg@1fb80000 { + compatible = "mediatek,generic-pciecfg", "syscon"; + reg = <0x1fb80000 0x1000>; + }; + + pcie0: pcie@1fb81000 { + compatible = "econet,en7528-pcie"; + device_type = "pci"; + reg = <0x1fb81000 0x1000>; + reg-names = "port0"; + linux,pci-domain = <0>; + #address-cells = <3>; + #size-cells = <2>; + interrupt-parent = <&intc>; + interrupts = <23>; + interrupt-names = "pcie_irq"; + clocks = <&scuclk EN751221_CLK_PCIE>; + clock-names = "sys_ck0"; + phys = <&pcie_phy0>; + phy-names = "pcie-phy0"; + bus-range = <0x00 0xff>; + ranges = <0x01000000 0 0x00000000 0x1f600000 0 0x00008000>, + <0x82000000 0 0x20000000 0x20000000 0 0x08000000>; + status = "disabled"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie_intc0 0>, + <0 0 0 2 &pcie_intc0 1>, + <0 0 0 3 &pcie_intc0 2>, + <0 0 0 4 &pcie_intc0 3>; + + pcie_intc0: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + + slot0: pcie@0,0 { + reg = <0x0000 0 0 0 0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; + }; + }; + + pcie1: pcie@1fb83000 { + compatible = "econet,en7528-pcie"; + device_type = "pci"; + reg = <0x1fb83000 0x1000>; + reg-names = "port1"; + linux,pci-domain = <1>; + #address-cells = <3>; + #size-cells = <2>; + interrupt-parent = <&intc>; + interrupts = <24>; + interrupt-names = "pcie_irq"; + clocks = <&scuclk EN751221_CLK_PCIE>; + clock-names = "sys_ck1"; + phys = <&pcie_phy1>; + phy-names = "pcie-phy1"; + bus-range = <0x00 0xff>; + ranges = <0x81000000 0 0x00000000 0x1f608000 0 0x00008000>, + <0x82000000 0 0x28000000 0x28000000 0 0x08000000>; + status = "disabled"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie_intc1 0>, + <0 0 0 2 &pcie_intc1 1>, + <0 0 0 3 &pcie_intc1 2>, + <0 0 0 4 &pcie_intc1 3>; + + pcie_intc1: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + + slot1: pcie@1,0 { + reg = <0x0800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + }; + }; + uart: serial@1fbf0000 { compatible = "ns16550"; reg = <0x1fbf0000 0x30>; diff --git a/arch/mips/boot/dts/econet/en751221_smartfiber_xp8421-b.dts b/arch/mips/boot/dts/econet/en751221_smartfiber_xp8421-b.dts index 8223c5bce67f..c633bf73add6 100644 --- a/arch/mips/boot/dts/econet/en751221_smartfiber_xp8421-b.dts +++ b/arch/mips/boot/dts/econet/en751221_smartfiber_xp8421-b.dts @@ -17,3 +17,24 @@ chosen { linux,usable-memory-range = <0x00020000 0x1bfe0000>; }; }; + +&pcie0 { + status = "okay"; +}; +&slot0 { + wifi@0,0 { + /* MT7612E */ + compatible = "mediatek,mt76"; + reg = <0x0000 0 0 0 0>; + }; +}; +&pcie1 { + status = "okay"; +}; +&slot1 { + wifi@0,0 { + /* MT7592 */ + compatible = "mediatek,mt76"; + reg = <0x0000 0 0 0 0>; + }; +}; diff --git a/arch/mips/econet/Kconfig b/arch/mips/econet/Kconfig index fd69884cc9a8..b37b9d25d5a4 100644 --- a/arch/mips/econet/Kconfig +++ b/arch/mips/econet/Kconfig @@ -13,7 +13,9 @@ choice bool "EN751221 family" select COMMON_CLK select ECONET_EN751221_INTC + select HAVE_PCI select IRQ_MIPS_CPU + select PCI_DRIVERS_GENERIC select SMP select SMP_UP select SYS_SUPPORTS_SMP From 3dbb08276836de58fc3097526c4bd9c3abe8f142 Mon Sep 17 00:00:00 2001 From: Shiji Yang Date: Wed, 18 Jun 2025 11:42:05 +0800 Subject: [PATCH 10/30] mips: pci-mt7620: fix bridge register access Host bridge registers and PCI RC control registers have different memory base. pcie_m32() is used to write the RC control registers instead of bridge registers. This patch introduces bridge_m32() and use it to operate bridge registers to fix the access issue. Signed-off-by: Shiji Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/pci/pci-mt7620.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/arch/mips/pci/pci-mt7620.c b/arch/mips/pci/pci-mt7620.c index 5c4bdf6919e5..94b3c96a1f48 100644 --- a/arch/mips/pci/pci-mt7620.c +++ b/arch/mips/pci/pci-mt7620.c @@ -87,6 +87,15 @@ static inline u32 bridge_r32(unsigned reg) return ioread32(bridge_base + reg); } +static inline void bridge_m32(u32 clr, u32 set, unsigned reg) +{ + u32 val = bridge_r32(reg); + + val &= ~clr; + val |= set; + bridge_w32(val, reg); +} + static inline void pcie_w32(u32 val, unsigned reg) { iowrite32(val, pcie_base + reg); @@ -228,7 +237,7 @@ static int mt7620_pci_hw_init(struct platform_device *pdev) pcie_phy(0x68, 0xB4); /* put core into reset */ - pcie_m32(0, PCIRST, RALINK_PCI_PCICFG_ADDR); + bridge_m32(PCIRST, PCIRST, RALINK_PCI_PCICFG_ADDR); reset_control_assert(rstpcie0); /* disable power and all clocks */ @@ -318,7 +327,7 @@ static int mt7620_pci_probe(struct platform_device *pdev) mdelay(50); /* enable write access */ - pcie_m32(PCIRST, 0, RALINK_PCI_PCICFG_ADDR); + bridge_m32(PCIRST, 0, RALINK_PCI_PCICFG_ADDR); mdelay(100); /* check if there is a card present */ @@ -340,7 +349,7 @@ static int mt7620_pci_probe(struct platform_device *pdev) pcie_w32(0x06040001, RALINK_PCI0_CLASS); /* enable interrupts */ - pcie_m32(0, PCIINT2, RALINK_PCI_PCIENA); + bridge_m32(PCIINT2, PCIINT2, RALINK_PCI_PCIENA); /* voodoo from the SDK driver */ pci_config_read(NULL, 0, 4, 4, &val); From c2631cc4508c2e331759b0e5481a03d6b4b76346 Mon Sep 17 00:00:00 2001 From: Shiji Yang Date: Wed, 18 Jun 2025 11:42:06 +0800 Subject: [PATCH 11/30] mips: pci-mt7620: add more register init values These missing register init values are ported from the vendor SDK. It should have some stability enhancements. Tested on both MT7620 and MT7628. Signed-off-by: Shiji Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/pci/pci-mt7620.c | 57 ++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/arch/mips/pci/pci-mt7620.c b/arch/mips/pci/pci-mt7620.c index 94b3c96a1f48..81a49b05fe5f 100644 --- a/arch/mips/pci/pci-mt7620.c +++ b/arch/mips/pci/pci-mt7620.c @@ -26,6 +26,8 @@ #define RALINK_INT_PCIE0 4 +#define RALINK_SYSCFG0 0x10 +#define RALINK_SYSCFG0_XTAL40 BIT(6) #define RALINK_CLKCFG1 0x30 #define RALINK_GPIOMODE 0x60 @@ -62,7 +64,7 @@ #define PCIEPHY0_CFG 0x90 -#define RALINK_PCIEPHY_P0_CTL_OFFSET 0x7498 +#define RALINK_PCIEPHY_P0_CTL_OFFSET 0x7000 #define RALINK_PCIE0_CLK_EN BIT(26) #define BUSY 0x80000000 @@ -115,6 +117,14 @@ static inline void pcie_m32(u32 clr, u32 set, unsigned reg) pcie_w32(val, reg); } +static inline void +pcie_phyctrl_set(unsigned offset, u32 b_start, u32 bits, u32 val) +{ + pcie_m32(GENMASK(b_start + bits - 1, b_start), + val << b_start, + RALINK_PCIEPHY_P0_CTL_OFFSET + offset); +} + static int wait_pciephy_busy(void) { unsigned long reg_value = 0x0, retry = 0; @@ -263,10 +273,8 @@ static int mt7620_pci_hw_init(struct platform_device *pdev) return 0; } -static int mt7628_pci_hw_init(struct platform_device *pdev) +static void mt7628_pci_hw_init(struct platform_device *pdev) { - u32 val = 0; - /* bring the core out of reset */ rt_sysc_m32(BIT(16), 0, RALINK_GPIOMODE); reset_control_deassert(rstpcie0); @@ -276,14 +284,33 @@ static int mt7628_pci_hw_init(struct platform_device *pdev) mdelay(100); /* voodoo from the SDK driver */ - pcie_m32(~0xff, 0x5, RALINK_PCIEPHY_P0_CTL_OFFSET); + pcie_phyctrl_set(0x400, 8, 1, 0x1); + pcie_phyctrl_set(0x400, 9, 2, 0x0); + pcie_phyctrl_set(0x000, 4, 1, 0x1); + pcie_phyctrl_set(0x000, 5, 1, 0x0); + pcie_phyctrl_set(0x4ac, 16, 3, 0x3); - pci_config_read(NULL, 0, 0x70c, 4, &val); - val &= ~(0xff) << 8; - val |= 0x50 << 8; - pci_config_write(NULL, 0, 0x70c, 4, val); + if (rt_sysc_r32(RALINK_SYSCFG0) & RALINK_SYSCFG0_XTAL40) { + pcie_phyctrl_set(0x4bc, 24, 8, 0x7d); + pcie_phyctrl_set(0x490, 12, 4, 0x08); + pcie_phyctrl_set(0x490, 6, 2, 0x01); + pcie_phyctrl_set(0x4c0, 0, 32, 0x1f400000); + pcie_phyctrl_set(0x4a4, 0, 16, 0x013d); + pcie_phyctrl_set(0x4a8, 16, 16, 0x74); + pcie_phyctrl_set(0x4a8, 0, 16, 0x74); + } else { + pcie_phyctrl_set(0x4bc, 24, 8, 0x64); + pcie_phyctrl_set(0x490, 12, 4, 0x0a); + pcie_phyctrl_set(0x490, 6, 2, 0x00); + pcie_phyctrl_set(0x4c0, 0, 32, 0x19000000); + pcie_phyctrl_set(0x4a4, 0, 16, 0x018d); + pcie_phyctrl_set(0x4a8, 16, 16, 0x4a); + pcie_phyctrl_set(0x4a8, 0, 16, 0x4a); + } - return 0; + pcie_phyctrl_set(0x498, 0, 8, 0x5); + pcie_phyctrl_set(0x000, 5, 1, 0x1); + pcie_phyctrl_set(0x000, 4, 1, 0x0); } static int mt7620_pci_probe(struct platform_device *pdev) @@ -316,8 +343,7 @@ static int mt7620_pci_probe(struct platform_device *pdev) case MT762X_SOC_MT7628AN: case MT762X_SOC_MT7688: - if (mt7628_pci_hw_init(pdev)) - return -1; + mt7628_pci_hw_init(pdev); break; default: @@ -336,6 +362,8 @@ static int mt7620_pci_probe(struct platform_device *pdev) rt_sysc_m32(RALINK_PCIE0_CLK_EN, 0, RALINK_CLKCFG1); if (ralink_soc == MT762X_SOC_MT7620A) rt_sysc_m32(LC_CKDRVPD, PDRV_SW_SET, PPLL_DRV); + else + pcie_phyctrl_set(0x000, 0, 32, 0x10); dev_info(&pdev->dev, "PCIE0 no card, disable it(RST&CLK)\n"); return -1; } @@ -355,6 +383,11 @@ static int mt7620_pci_probe(struct platform_device *pdev) pci_config_read(NULL, 0, 4, 4, &val); pci_config_write(NULL, 0, 4, 4, val | 0x7); + pci_config_read(NULL, 0, 0x70c, 4, &val); + val &= ~(0xff) << 8; + val |= 0x50 << 8; + pci_config_write(NULL, 0, 0x70c, 4, val); + pci_load_of_ranges(&mt7620_controller, pdev->dev.of_node); register_pci_controller(&mt7620_controller); From 2300d68e577909c7d3013910ff818e8572288491 Mon Sep 17 00:00:00 2001 From: Shiji Yang Date: Wed, 18 Jun 2025 11:42:07 +0800 Subject: [PATCH 12/30] mips: pci-mt7620: rework initialization procedure Move the reset operation to the common part to reduce the code redundancy. They are actually the same and needed for all SoCs. Disabling power and clock are unnecessary for MT7620 and will be removed. In vendor SDK, it's used to save the power when the PCI driver is not selected. The MT7628 GPIO pinctrl has been removed because this should be done in device-tree. Some delay intervals have also been increased to follow the recommendations of the SoC SDK and datasheet. Tested on both MT7620 and MT7628. Signed-off-by: Shiji Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/pci/pci-mt7620.c | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/arch/mips/pci/pci-mt7620.c b/arch/mips/pci/pci-mt7620.c index 81a49b05fe5f..aae844f27a7e 100644 --- a/arch/mips/pci/pci-mt7620.c +++ b/arch/mips/pci/pci-mt7620.c @@ -29,7 +29,6 @@ #define RALINK_SYSCFG0 0x10 #define RALINK_SYSCFG0_XTAL40 BIT(6) #define RALINK_CLKCFG1 0x30 -#define RALINK_GPIOMODE 0x60 #define PPLL_CFG1 0x9c #define PPLL_LD BIT(23) @@ -246,19 +245,6 @@ static int mt7620_pci_hw_init(struct platform_device *pdev) /* Elastic buffer control */ pcie_phy(0x68, 0xB4); - /* put core into reset */ - bridge_m32(PCIRST, PCIRST, RALINK_PCI_PCICFG_ADDR); - reset_control_assert(rstpcie0); - - /* disable power and all clocks */ - rt_sysc_m32(RALINK_PCIE0_CLK_EN, 0, RALINK_CLKCFG1); - rt_sysc_m32(LC_CKDRVPD, PDRV_SW_SET, PPLL_DRV); - - /* bring core out of reset */ - reset_control_deassert(rstpcie0); - rt_sysc_m32(0, RALINK_PCIE0_CLK_EN, RALINK_CLKCFG1); - mdelay(100); - if (!(rt_sysc_r32(PPLL_CFG1) & PPLL_LD)) { dev_err(&pdev->dev, "pcie PLL not locked, aborting init\n"); reset_control_assert(rstpcie0); @@ -275,14 +261,6 @@ static int mt7620_pci_hw_init(struct platform_device *pdev) static void mt7628_pci_hw_init(struct platform_device *pdev) { - /* bring the core out of reset */ - rt_sysc_m32(BIT(16), 0, RALINK_GPIOMODE); - reset_control_deassert(rstpcie0); - - /* enable the pci clk */ - rt_sysc_m32(0, RALINK_PCIE0_CLK_EN, RALINK_CLKCFG1); - mdelay(100); - /* voodoo from the SDK driver */ pcie_phyctrl_set(0x400, 8, 1, 0x1); pcie_phyctrl_set(0x400, 9, 2, 0x0); @@ -334,6 +312,16 @@ static int mt7620_pci_probe(struct platform_device *pdev) ioport_resource.start = 0; ioport_resource.end = ~0; + /* reset PCIe controller */ + reset_control_assert(rstpcie0); + msleep(100); + reset_control_deassert(rstpcie0); + rt_sysc_m32(0, RALINK_PCIE0_CLK_EN, RALINK_CLKCFG1); + msleep(100); + + /* assert PERST_N pin */ + bridge_m32(PCIRST, PCIRST, RALINK_PCI_PCICFG_ADDR); + /* bring up the pci core */ switch (ralink_soc) { case MT762X_SOC_MT7620A: @@ -350,11 +338,11 @@ static int mt7620_pci_probe(struct platform_device *pdev) dev_err(&pdev->dev, "pcie is not supported on this hardware\n"); return -1; } - mdelay(50); + msleep(500); - /* enable write access */ + /* deassert PERST_N pin and wait PCIe peripheral init */ bridge_m32(PCIRST, 0, RALINK_PCI_PCICFG_ADDR); - mdelay(100); + msleep(1000); /* check if there is a card present */ if ((pcie_r32(RALINK_PCI0_STATUS) & PCIE_LINK_UP_ST) == 0) { From 79b888ee4c6387bc07c5452bfd031cb985871a5f Mon Sep 17 00:00:00 2001 From: Rong Zhang Date: Mon, 16 Mar 2026 02:44:00 +0800 Subject: [PATCH 13/30] MIPS: dts: loongson64g-package: Switch to Loongson UART driver Loongson64g is Loongson 3A4000, whose UART controller is compatible with Loongson 2K1500, which is NS16550A-compatible with an additional fractional frequency divisor register. Update the compatible strings to reflect this, so that 3A4000 can benefit from the fractional frequency divisor provided by loongson-uart. This is required on some devices, otherwise their UART can't work at some high baud rates, e.g., 115200. Tested on Loongson-LS3A4000-7A1000-NUC-SE with a 25MHz UART clock. Without fractional frequency divisor, the actual baud rate was 111607 (25MHz / 16 / 14, measured value: 111545) and some USB-to-UART converters couldn't work with it at all. With fractional frequency divisor, the measured baud rate becomes 115207, which is quite accurate. Signed-off-by: Rong Zhang Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/loongson/loongson64g-package.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/boot/dts/loongson/loongson64g-package.dtsi b/arch/mips/boot/dts/loongson/loongson64g-package.dtsi index d4314f62ccc2..029daeedd0ab 100644 --- a/arch/mips/boot/dts/loongson/loongson64g-package.dtsi +++ b/arch/mips/boot/dts/loongson/loongson64g-package.dtsi @@ -40,7 +40,7 @@ liointc: interrupt-controller@3ff01400 { }; cpu_uart0: serial@1fe00100 { - compatible = "ns16550a"; + compatible = "loongson,ls3a4000-uart", "loongson,ls2k1500-uart", "ns16550a"; reg = <0 0x1fe00100 0x10>; clock-frequency = <100000000>; interrupt-parent = <&liointc>; @@ -50,7 +50,7 @@ cpu_uart0: serial@1fe00100 { cpu_uart1: serial@1fe00110 { status = "disabled"; - compatible = "ns16550a"; + compatible = "loongson,ls3a4000-uart", "loongson,ls2k1500-uart", "ns16550a"; reg = <0 0x1fe00110 0x10>; clock-frequency = <100000000>; interrupts = <15 IRQ_TYPE_LEVEL_HIGH>; From 20e65a6dd85cbd8aa8d1e15e55a3d180516e09d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Monin?= Date: Mon, 16 Mar 2026 16:25:38 +0100 Subject: [PATCH 14/30] dt-bindings: mips: Add Mobileye EyeQ6Lplus SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an entry to the mobileye bindings for the EyeQ6Lplus which is part of the EyeQ family of system-on-chip. Reviewed-by: Rob Herring (Arm) Signed-off-by: Benoît Monin Signed-off-by: Thomas Bogendoerfer --- Documentation/devicetree/bindings/mips/mobileye.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/mips/mobileye.yaml b/Documentation/devicetree/bindings/mips/mobileye.yaml index d60744550e46..83abe268e96b 100644 --- a/Documentation/devicetree/bindings/mips/mobileye.yaml +++ b/Documentation/devicetree/bindings/mips/mobileye.yaml @@ -31,6 +31,11 @@ properties: - enum: - mobileye,eyeq6h-epm6 - const: mobileye,eyeq6h + - description: Boards with Mobileye EyeQ6Lplus SoC + items: + - enum: + - mobileye,eyeq6lplus-epm6 + - const: mobileye,eyeq6lplus additionalProperties: true From 4434c3896fab5f284469182a3cdf7cd46a7f11ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Monin?= Date: Mon, 16 Mar 2026 16:25:39 +0100 Subject: [PATCH 15/30] dt-bindings: soc: mobileye: Add EyeQ6Lplus OLB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Other Logic Block" found in the EyeQ6Lplus from Mobileye provides various functions for the controllers present in the SoC. The OLB produces 22 clocks derived from its input, which is connected to the main oscillator of the SoC. It provides reset signals via two reset domains. It also controls 32 pins to be either a GPIO or an alternate function. Reviewed-by: Rob Herring (Arm) Signed-off-by: Benoît Monin Reviewed-by: Linus Walleij Acked-by: Stephen Boyd Signed-off-by: Thomas Bogendoerfer --- .../soc/mobileye/mobileye,eyeq6lplus-olb.yaml | 208 ++++++++++++++++++ .../clock/mobileye,eyeq6lplus-clk.h | 37 ++++ 2 files changed, 245 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq6lplus-olb.yaml create mode 100644 include/dt-bindings/clock/mobileye,eyeq6lplus-clk.h diff --git a/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq6lplus-olb.yaml b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq6lplus-olb.yaml new file mode 100644 index 000000000000..8334876cf4e6 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq6lplus-olb.yaml @@ -0,0 +1,208 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/mobileye/mobileye,eyeq6lplus-olb.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mobileye EyeQ6Lplus SoC system controller + +maintainers: + - Benoît Monin + - Grégory Clement + - Théo Lebrun + - Vladimir Kondratiev + +description: + OLB ("Other Logic Block") is a hardware block grouping smaller blocks. + Clocks, resets, pinctrl are being handled from here. EyeQ6Lplus hosts + a single instance providing 22 clocks, two reset domains and one bank + of 32 pins. + +properties: + compatible: + items: + - const: mobileye,eyeq6lplus-olb + - const: syscon + + reg: + maxItems: 1 + + '#reset-cells': + description: + First cell is reset domain index. + Second cell is reset index inside that domain. + const: 2 + + '#clock-cells': + const: 1 + + clocks: + maxItems: 1 + description: + Input parent clock to all PLLs. Expected to be the main crystal. + + clock-names: + const: ref + +patternProperties: + '-pins?$': + type: object + description: Pin muxing configuration. + $ref: /schemas/pinctrl/pinmux-node.yaml# + additionalProperties: false + properties: + pins: true + function: + enum: [gpio, timer0, timer1, uart_ssi, spi0, uart0, timer2, timer3, + timer_ext0, spi1, timer_ext1, ext_ref_clk, mipi_ref_clk] + bias-disable: true + bias-pull-down: true + bias-pull-up: true + drive-strength: true + required: + - pins + - function + allOf: + - if: + properties: + function: + const: gpio + then: + properties: + pins: + items: # PA0 - PA31 + pattern: '^(PA[1,2]?[0-9]|PA3[0,1])$' + - if: + properties: + function: + const: timer0 + then: + properties: + pins: + items: + enum: [PA0, PA1] + - if: + properties: + function: + const: timer1 + then: + properties: + pins: + items: + enum: [PA2, PA3] + - if: + properties: + function: + const: uart_ssi + then: + properties: + pins: + items: + enum: [PA4, PA5] + - if: + properties: + function: + const: spi0 + then: + properties: + pins: + items: + enum: [PA6, PA7, PA8, PA9, PA10] + - if: + properties: + function: + const: uart0 + then: + properties: + pins: + items: + enum: [PA11, PA12] + - if: + properties: + function: + const: timer2 + then: + properties: + pins: + items: + enum: [PA13, PA14] + - if: + properties: + function: + const: timer3 + then: + properties: + pins: + items: + enum: [PA15, PA16] + - if: + properties: + function: + const: timer_ext0 + then: + properties: + pins: + items: + enum: [PA17, PA18, PA19, PA20] + - if: + properties: + function: + const: spi1 + then: + properties: + pins: + items: + enum: [PA21, PA22, PA23, PA24, PA25] + - if: + properties: + function: + const: timer_ext1 + then: + properties: + pins: + items: + enum: [PA26, PA27, PA28, PA29] + - if: + properties: + function: + const: ext_ref_clk + then: + properties: + pins: + items: + enum: [PA30] + - if: + properties: + function: + const: mipi_ref_clk + then: + properties: + pins: + items: + enum: [PA31] + +required: + - compatible + - reg + - '#clock-cells' + - clocks + - clock-names + - '#reset-cells' + +additionalProperties: false + +examples: + - | + soc { + #address-cells = <2>; + #size-cells = <2>; + + system-controller@e8400000 { + compatible = "mobileye,eyeq6lplus-olb", "syscon"; + reg = <0 0xe8400000 0x0 0x80000>; + #reset-cells = <2>; + #clock-cells = <1>; + clocks = <&xtal>; + clock-names = "ref"; + }; + }; diff --git a/include/dt-bindings/clock/mobileye,eyeq6lplus-clk.h b/include/dt-bindings/clock/mobileye,eyeq6lplus-clk.h new file mode 100644 index 000000000000..20d84ee24ad5 --- /dev/null +++ b/include/dt-bindings/clock/mobileye,eyeq6lplus-clk.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (C) 2025 Mobileye Vision Technologies Ltd. + */ + +#ifndef _DT_BINDINGS_CLOCK_MOBILEYE_EYEQ6LPLUS_CLK_H +#define _DT_BINDINGS_CLOCK_MOBILEYE_EYEQ6LPLUS_CLK_H + +#define EQ6LPC_PLL_CPU 0 +#define EQ6LPC_PLL_DDR 1 +#define EQ6LPC_PLL_PER 2 +#define EQ6LPC_PLL_VDI 3 +#define EQ6LPC_PLL_ACC 4 + +#define EQ6LPC_CPU_OCC 5 + +#define EQ6LPC_ACC_VDI 6 +#define EQ6LPC_ACC_OCC 7 +#define EQ6LPC_ACC_FCMU 8 + +#define EQ6LPC_DDR_OCC 9 + +#define EQ6LPC_PER_OCC 10 +#define EQ6LPC_PER_I2C_SER 11 +#define EQ6LPC_PER_PCLK 12 +#define EQ6LPC_PER_TSU 13 +#define EQ6LPC_PER_OSPI 14 +#define EQ6LPC_PER_GPIO 15 +#define EQ6LPC_PER_TIMER 16 +#define EQ6LPC_PER_I2C 17 +#define EQ6LPC_PER_UART 18 +#define EQ6LPC_PER_SPI 19 +#define EQ6LPC_PER_PERIPH 20 + +#define EQ6LPC_VDI_OCC 21 + +#endif From 2aca86de974b309e86025644f186b82e7805c352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Monin?= Date: Mon, 16 Mar 2026 16:25:40 +0100 Subject: [PATCH 16/30] MIPS: Add Mobileye EyeQ6Lplus support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the EyeQ6Lplus to the group of choices for Mobileye SoC and set the kernel load address specific to this SoC. Signed-off-by: Benoît Monin Signed-off-by: Thomas Bogendoerfer --- arch/mips/mobileye/Kconfig | 3 +++ arch/mips/mobileye/Platform | 1 + 2 files changed, 4 insertions(+) diff --git a/arch/mips/mobileye/Kconfig b/arch/mips/mobileye/Kconfig index f9abb2d6e178..8a4868d2e28f 100644 --- a/arch/mips/mobileye/Kconfig +++ b/arch/mips/mobileye/Kconfig @@ -12,6 +12,9 @@ choice config MACH_EYEQ6H bool "Mobileye EyeQ6H SoC" + + config MACH_EYEQ6LPLUS + bool "Mobileye EyeQ6Lplus SoC" endchoice config FIT_IMAGE_FDT_EPM5 diff --git a/arch/mips/mobileye/Platform b/arch/mips/mobileye/Platform index 69f775bbbb1e..93b533492b58 100644 --- a/arch/mips/mobileye/Platform +++ b/arch/mips/mobileye/Platform @@ -10,6 +10,7 @@ load-$(CONFIG_MACH_EYEQ5) = 0xa800000808000000 load-$(CONFIG_MACH_EYEQ6H) = 0xa800000100800000 +load-$(CONFIG_MACH_EYEQ6LPLUS) = 0xa800000108800000 all-$(CONFIG_MACH_EYEQ5) += vmlinux.gz.itb its-y := vmlinux.its.S From 36cab4bd8ba3145b3c4e197cdf20596279036ab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Monin?= Date: Mon, 16 Mar 2026 16:25:41 +0100 Subject: [PATCH 17/30] reset: eyeq: Add Mobileye EyeQ6Lplus OLB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Declare the two reset domains found in the EyeQ6Lplus OLB and add them to the data matched by 'mobileye,eyeq6lplus-olb' compatible. Those reset domains are identical to those present in the EyeQ5 OLB, so no changes are needed to support them. Also select reset-eyeq for all EYEQ SoCs instead of listing each one individually, as it is needed by all Mobileye EyeQ SoC. Reviewed-by: Philipp Zabel Signed-off-by: Benoît Monin Signed-off-by: Thomas Bogendoerfer --- drivers/reset/Kconfig | 4 ++-- drivers/reset/reset-eyeq.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 7ce151f6a7e4..67057248c810 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -85,9 +85,9 @@ config RESET_EIC7700 config RESET_EYEQ bool "Mobileye EyeQ reset controller" - depends on MACH_EYEQ5 || MACH_EYEQ6H || COMPILE_TEST + depends on EYEQ || COMPILE_TEST select AUXILIARY_BUS - default MACH_EYEQ5 || MACH_EYEQ6H + default EYEQ help This enables the Mobileye EyeQ reset controller, used in EyeQ5, EyeQ6L and EyeQ6H SoCs. diff --git a/drivers/reset/reset-eyeq.c b/drivers/reset/reset-eyeq.c index 2d3998368a1c..791b7283111e 100644 --- a/drivers/reset/reset-eyeq.c +++ b/drivers/reset/reset-eyeq.c @@ -49,6 +49,18 @@ * 8. MPC0 9. MPC1 10. MPC2 11. MPC3 * 12. MPC4 * + * Known resets in EyeQ6Lplus domain 0 (type EQR_EYEQ5_PCIE): + * 0. SPI0 1. SPI1 2. UART0 3. I2C0 + * 4. I2C1 5. TIMER0 6. TIMER1 7. TIMER2 + * 8. TIMER3 9. WD0 10. WD1 11. EXT0 + * 12. EXT1 13. GPIO + * + * Known resets in EyeQ6Lplus domain 1 (type EQR_EYEQ5_ACRP): + * 0. VMP0 1. VMP1 2. VMP2 3. VMP3 + * 4. PMA0 5. PMA1 6. PMAC0 7. PMAC1 + * 8. MPC0 9. MPC1 10. MPC2 11. MPC3 + * 12. MPC4 + * * Known resets in EyeQ6H west/east (type EQR_EYEQ6H_SARCR): * 0. CAN 1. SPI0 2. SPI1 3. UART0 * 4. UART1 5. I2C0 6. I2C1 7. -hole- @@ -521,6 +533,24 @@ static const struct eqr_match_data eqr_eyeq6l_data = { .domains = eqr_eyeq6l_domains, }; +static const struct eqr_domain_descriptor eqr_eyeq6lplus_domains[] = { + { + .type = EQR_EYEQ5_PCIE, + .valid_mask = 0x3FFF, + .offset = 0x004, + }, + { + .type = EQR_EYEQ5_ACRP, + .valid_mask = 0x00FF, + .offset = 0x200, + }, +}; + +static const struct eqr_match_data eqr_eyeq6lplus_data = { + .domain_count = ARRAY_SIZE(eqr_eyeq6lplus_domains), + .domains = eqr_eyeq6lplus_domains, +}; + /* West and east OLBs each have an instance. */ static const struct eqr_domain_descriptor eqr_eyeq6h_we_domains[] = { { @@ -555,6 +585,7 @@ static const struct eqr_match_data eqr_eyeq6h_acc_data = { static const struct of_device_id eqr_match_table[] = { { .compatible = "mobileye,eyeq5-olb", .data = &eqr_eyeq5_data }, { .compatible = "mobileye,eyeq6l-olb", .data = &eqr_eyeq6l_data }, + { .compatible = "mobileye,eyeq6lplus-olb", .data = &eqr_eyeq6lplus_data }, { .compatible = "mobileye,eyeq6h-west-olb", .data = &eqr_eyeq6h_we_data }, { .compatible = "mobileye,eyeq6h-east-olb", .data = &eqr_eyeq6h_we_data }, { .compatible = "mobileye,eyeq6h-acc-olb", .data = &eqr_eyeq6h_acc_data }, From 7cfa9474b91e8ed53f7d4f7b9ac42358929dc2eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Monin?= Date: Mon, 16 Mar 2026 16:25:42 +0100 Subject: [PATCH 18/30] pinctrl: eyeq5: Use match data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using the pin descriptions, pin functions and register offsets of the EyeQ5 directly, access those via a pointer to a newly introduced struct eq5p_match_data. This structure contains, in addition to the pin descriptions and pin functions, an array of pin banks. Each bank holds the number of pins and the register offsets. All functions accessing a pin now use a pointer to a bank structure and an offset inside that bank. The conversion from a pin number to a bank and an offset is done in the new function eq5p_pin_to_bank_offset(), which replace eq5p_pin_to_bank() and eq5p_pin_to_offset(). All the data related to the EyeQ5 is declared with the eq5p_eyeq5_ prefix to distinguish it from the common code. During the probe, we use the parent OF node to get the match data. We cannot directly use an OF node since pinctrl-eyeq5 is an auxiliary device of clk-eyeq. Signed-off-by: Benoît Monin Reviewed-by: Linus Walleij Signed-off-by: Thomas Bogendoerfer --- drivers/pinctrl/pinctrl-eyeq5.c | 342 ++++++++++++++++++++------------ 1 file changed, 213 insertions(+), 129 deletions(-) diff --git a/drivers/pinctrl/pinctrl-eyeq5.c b/drivers/pinctrl/pinctrl-eyeq5.c index 5f6af934a516..c780af09cde9 100644 --- a/drivers/pinctrl/pinctrl-eyeq5.c +++ b/drivers/pinctrl/pinctrl-eyeq5.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -38,18 +39,6 @@ #include "core.h" #include "pinctrl-utils.h" -struct eq5p_pinctrl { - struct pinctrl_desc desc; - void __iomem *base; -}; - -enum eq5p_bank { - EQ5P_BANK_A, - EQ5P_BANK_B, - - EQ5P_BANK_COUNT, -}; - enum eq5p_regs { EQ5P_PD, EQ5P_PU, @@ -60,9 +49,24 @@ enum eq5p_regs { EQ5P_REG_COUNT, }; -static const unsigned int eq5p_regs[EQ5P_BANK_COUNT][EQ5P_REG_COUNT] = { - [EQ5P_BANK_A] = {0x0C0, 0x0C4, 0x0D0, 0x0D4, 0x0B0}, - [EQ5P_BANK_B] = {0x0C8, 0x0CC, 0x0D8, 0x0DC, 0x0B4}, +struct eq5p_bank { + const unsigned int npins; + const unsigned int regs[EQ5P_REG_COUNT]; +}; + +struct eq5p_match_data { + const unsigned int npins; + const unsigned int nfunctions; + const unsigned int nbanks; + const struct pinctrl_pin_desc *pins; + const struct pinfunction *functions; + const struct eq5p_bank *banks; +}; + +struct eq5p_pinctrl { + struct pinctrl_desc desc; + void __iomem *base; + const struct eq5p_match_data *data; }; /* @@ -70,10 +74,18 @@ static const unsigned int eq5p_regs[EQ5P_BANK_COUNT][EQ5P_REG_COUNT] = { */ #define EQ5P_DS_MASK GENMASK(1, 0) +/* + * The GPIO function is always the first function + */ +#define EQ5P_GPIO_FUNC_SELECTOR 0 + +/* Helper to declare pinfunction */ +#define EQ5P_PINFUNCTION(func, groups) PINCTRL_PINFUNCTION(func, groups, ARRAY_SIZE(groups)) + /* * Comments to the right of each pin are the "signal name" in the datasheet. */ -static const struct pinctrl_pin_desc eq5p_pins[] = { +static const struct pinctrl_pin_desc eq5p_eyeq5_pins[] = { /* Bank A */ PINCTRL_PIN(0, "PA0"), /* A0_TIMER0_CK */ PINCTRL_PIN(1, "PA1"), /* A1_TIMER0_EOC */ @@ -105,35 +117,35 @@ static const struct pinctrl_pin_desc eq5p_pins[] = { PINCTRL_PIN(27, "PA27"), /* A27_SPI_1_CS1 */ PINCTRL_PIN(28, "PA28"), /* A28_REF_CLK0 */ -#define EQ5P_PIN_OFFSET_BANK_B 29 +#define EQ5P_EYEQ5_PIN_OFFSET_BANK_B 29 /* Bank B */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 0, "PB0"), /* B0_TIMER3_CK */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 1, "PB1"), /* B1_TIMER3_EOC */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 2, "PB2"), /* B2_TIMER4_CK */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 3, "PB3"), /* B3_TIMER4_EOC */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 4, "PB4"), /* B4_TIMER6_EXT_INCAP1 */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 5, "PB5"), /* B5_TIMER6_EXT_INCAP2 */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 6, "PB6"), /* B6_TIMER6_EXT_OUTCMP1 */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 7, "PB7"), /* B7_TIMER6_EXT_OUTCMP2 */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 8, "PB8"), /* B8_UART_2_TX */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 9, "PB9"), /* B9_UART_2_RX */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 10, "PB10"), /* B10_CAN_2_TX */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 11, "PB11"), /* B11_CAN_2_RX */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 12, "PB12"), /* B12_SPI_2_DO */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 13, "PB13"), /* B13_SPI_2_DI */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 14, "PB14"), /* B14_SPI_2_CK */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 15, "PB15"), /* B15_SPI_2_CS0 */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 16, "PB16"), /* B16_SPI_2_CS1 */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 17, "PB17"), /* B17_SPI_3_DO */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 18, "PB18"), /* B18_SPI_3_DI */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 19, "PB19"), /* B19_SPI_3_CK */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 20, "PB20"), /* B20_SPI_3_CS0 */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 21, "PB21"), /* B21_SPI_3_CS1 */ - PINCTRL_PIN(EQ5P_PIN_OFFSET_BANK_B + 22, "PB22"), /* B22_MCLK0 */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 0, "PB0"), /* B0_TIMER3_CK */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 1, "PB1"), /* B1_TIMER3_EOC */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 2, "PB2"), /* B2_TIMER4_CK */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 3, "PB3"), /* B3_TIMER4_EOC */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 4, "PB4"), /* B4_TIMER6_EXT_INCAP1 */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 5, "PB5"), /* B5_TIMER6_EXT_INCAP2 */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 6, "PB6"), /* B6_TIMER6_EXT_OUTCMP1 */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 7, "PB7"), /* B7_TIMER6_EXT_OUTCMP2 */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 8, "PB8"), /* B8_UART_2_TX */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 9, "PB9"), /* B9_UART_2_RX */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 10, "PB10"), /* B10_CAN_2_TX */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 11, "PB11"), /* B11_CAN_2_RX */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 12, "PB12"), /* B12_SPI_2_DO */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 13, "PB13"), /* B13_SPI_2_DI */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 14, "PB14"), /* B14_SPI_2_CK */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 15, "PB15"), /* B15_SPI_2_CS0 */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 16, "PB16"), /* B16_SPI_2_CS1 */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 17, "PB17"), /* B17_SPI_3_DO */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 18, "PB18"), /* B18_SPI_3_DI */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 19, "PB19"), /* B19_SPI_3_CK */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 20, "PB20"), /* B20_SPI_3_CS0 */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 21, "PB21"), /* B21_SPI_3_CS1 */ + PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 22, "PB22"), /* B22_MCLK0 */ }; -static const char * const gpio_groups[] = { +static const char * const eq5p_eyeq5_gpio_groups[] = { /* Bank A */ "PA0", "PA1", "PA2", "PA3", "PA4", "PA5", "PA6", "PA7", "PA8", "PA9", "PA10", "PA11", "PA12", "PA13", "PA14", "PA15", @@ -147,70 +159,90 @@ static const char * const gpio_groups[] = { }; /* Groups of functions on bank A */ -static const char * const timer0_groups[] = { "PA0", "PA1" }; -static const char * const timer1_groups[] = { "PA2", "PA3" }; -static const char * const timer2_groups[] = { "PA4", "PA5" }; -static const char * const timer5_groups[] = { "PA6", "PA7", "PA8", "PA9" }; -static const char * const uart0_groups[] = { "PA10", "PA11" }; -static const char * const uart1_groups[] = { "PA12", "PA13" }; -static const char * const can0_groups[] = { "PA14", "PA15" }; -static const char * const can1_groups[] = { "PA16", "PA17" }; -static const char * const spi0_groups[] = { "PA18", "PA19", "PA20", "PA21", "PA22" }; -static const char * const spi1_groups[] = { "PA23", "PA24", "PA25", "PA26", "PA27" }; -static const char * const refclk0_groups[] = { "PA28" }; +static const char * const eq5p_eyeq5_timer0_groups[] = { "PA0", "PA1" }; +static const char * const eq5p_eyeq5_timer1_groups[] = { "PA2", "PA3" }; +static const char * const eq5p_eyeq5_timer2_groups[] = { "PA4", "PA5" }; +static const char * const eq5p_eyeq5_timer5_groups[] = { "PA6", "PA7", "PA8", "PA9" }; +static const char * const eq5p_eyeq5_uart0_groups[] = { "PA10", "PA11" }; +static const char * const eq5p_eyeq5_uart1_groups[] = { "PA12", "PA13" }; +static const char * const eq5p_eyeq5_can0_groups[] = { "PA14", "PA15" }; +static const char * const eq5p_eyeq5_can1_groups[] = { "PA16", "PA17" }; +static const char * const eq5p_eyeq5_spi0_groups[] = { "PA18", "PA19", "PA20", "PA21", "PA22" }; +static const char * const eq5p_eyeq5_spi1_groups[] = { "PA23", "PA24", "PA25", "PA26", "PA27" }; +static const char * const eq5p_eyeq5_refclk0_groups[] = { "PA28" }; /* Groups of functions on bank B */ -static const char * const timer3_groups[] = { "PB0", "PB1" }; -static const char * const timer4_groups[] = { "PB2", "PB3" }; -static const char * const timer6_groups[] = { "PB4", "PB5", "PB6", "PB7" }; -static const char * const uart2_groups[] = { "PB8", "PB9" }; -static const char * const can2_groups[] = { "PB10", "PB11" }; -static const char * const spi2_groups[] = { "PB12", "PB13", "PB14", "PB15", "PB16" }; -static const char * const spi3_groups[] = { "PB17", "PB18", "PB19", "PB20", "PB21" }; -static const char * const mclk0_groups[] = { "PB22" }; +static const char * const eq5p_eyeq5_timer3_groups[] = { "PB0", "PB1" }; +static const char * const eq5p_eyeq5_timer4_groups[] = { "PB2", "PB3" }; +static const char * const eq5p_eyeq5_timer6_groups[] = { "PB4", "PB5", "PB6", "PB7" }; +static const char * const eq5p_eyeq5_uart2_groups[] = { "PB8", "PB9" }; +static const char * const eq5p_eyeq5_can2_groups[] = { "PB10", "PB11" }; +static const char * const eq5p_eyeq5_spi2_groups[] = { "PB12", "PB13", "PB14", "PB15", "PB16" }; +static const char * const eq5p_eyeq5_spi3_groups[] = { "PB17", "PB18", "PB19", "PB20", "PB21" }; +static const char * const eq5p_eyeq5_mclk0_groups[] = { "PB22" }; -static const struct pinfunction eq5p_functions[] = { - /* GPIO having a fixed index is depended upon, see GPIO_FUNC_SELECTOR. */ - PINCTRL_PINFUNCTION("gpio", gpio_groups, ARRAY_SIZE(gpio_groups)), -#define GPIO_FUNC_SELECTOR 0 +static const struct pinfunction eq5p_eyeq5_functions[] = { + /* GPIO having a fixed index is depended upon, see EQ5P_GPIO_FUNC_SELECTOR. */ + EQ5P_PINFUNCTION("gpio", eq5p_eyeq5_gpio_groups), /* Bank A functions */ - PINCTRL_PINFUNCTION("timer0", timer0_groups, ARRAY_SIZE(timer0_groups)), - PINCTRL_PINFUNCTION("timer1", timer1_groups, ARRAY_SIZE(timer1_groups)), - PINCTRL_PINFUNCTION("timer2", timer2_groups, ARRAY_SIZE(timer2_groups)), - PINCTRL_PINFUNCTION("timer5", timer5_groups, ARRAY_SIZE(timer5_groups)), - PINCTRL_PINFUNCTION("uart0", uart0_groups, ARRAY_SIZE(uart0_groups)), - PINCTRL_PINFUNCTION("uart1", uart1_groups, ARRAY_SIZE(uart1_groups)), - PINCTRL_PINFUNCTION("can0", can0_groups, ARRAY_SIZE(can0_groups)), - PINCTRL_PINFUNCTION("can1", can1_groups, ARRAY_SIZE(can1_groups)), - PINCTRL_PINFUNCTION("spi0", spi0_groups, ARRAY_SIZE(spi0_groups)), - PINCTRL_PINFUNCTION("spi1", spi1_groups, ARRAY_SIZE(spi1_groups)), - PINCTRL_PINFUNCTION("refclk0", refclk0_groups, ARRAY_SIZE(refclk0_groups)), + EQ5P_PINFUNCTION("timer0", eq5p_eyeq5_timer0_groups), + EQ5P_PINFUNCTION("timer1", eq5p_eyeq5_timer1_groups), + EQ5P_PINFUNCTION("timer2", eq5p_eyeq5_timer2_groups), + EQ5P_PINFUNCTION("timer5", eq5p_eyeq5_timer5_groups), + EQ5P_PINFUNCTION("uart0", eq5p_eyeq5_uart0_groups), + EQ5P_PINFUNCTION("uart1", eq5p_eyeq5_uart1_groups), + EQ5P_PINFUNCTION("can0", eq5p_eyeq5_can0_groups), + EQ5P_PINFUNCTION("can1", eq5p_eyeq5_can1_groups), + EQ5P_PINFUNCTION("spi0", eq5p_eyeq5_spi0_groups), + EQ5P_PINFUNCTION("spi1", eq5p_eyeq5_spi1_groups), + EQ5P_PINFUNCTION("refclk0", eq5p_eyeq5_refclk0_groups), /* Bank B functions */ - PINCTRL_PINFUNCTION("timer3", timer3_groups, ARRAY_SIZE(timer3_groups)), - PINCTRL_PINFUNCTION("timer4", timer4_groups, ARRAY_SIZE(timer4_groups)), - PINCTRL_PINFUNCTION("timer6", timer6_groups, ARRAY_SIZE(timer6_groups)), - PINCTRL_PINFUNCTION("uart2", uart2_groups, ARRAY_SIZE(uart2_groups)), - PINCTRL_PINFUNCTION("can2", can2_groups, ARRAY_SIZE(can2_groups)), - PINCTRL_PINFUNCTION("spi2", spi2_groups, ARRAY_SIZE(spi2_groups)), - PINCTRL_PINFUNCTION("spi3", spi3_groups, ARRAY_SIZE(spi3_groups)), - PINCTRL_PINFUNCTION("mclk0", mclk0_groups, ARRAY_SIZE(mclk0_groups)), + EQ5P_PINFUNCTION("timer3", eq5p_eyeq5_timer3_groups), + EQ5P_PINFUNCTION("timer4", eq5p_eyeq5_timer4_groups), + EQ5P_PINFUNCTION("timer6", eq5p_eyeq5_timer6_groups), + EQ5P_PINFUNCTION("uart2", eq5p_eyeq5_uart2_groups), + EQ5P_PINFUNCTION("can2", eq5p_eyeq5_can2_groups), + EQ5P_PINFUNCTION("spi2", eq5p_eyeq5_spi2_groups), + EQ5P_PINFUNCTION("spi3", eq5p_eyeq5_spi3_groups), + EQ5P_PINFUNCTION("mclk0", eq5p_eyeq5_mclk0_groups), +}; + +static const struct eq5p_bank eq5p_eyeq5_banks[] = { + { + .npins = EQ5P_EYEQ5_PIN_OFFSET_BANK_B, + .regs = {0x0C0, 0x0C4, 0x0D0, 0x0D4, 0x0B0}, + }, + { + .npins = ARRAY_SIZE(eq5p_eyeq5_pins) - EQ5P_EYEQ5_PIN_OFFSET_BANK_B, + .regs = {0x0C8, 0x0CC, 0x0D8, 0x0DC, 0x0B4}, + }, +}; + +static const struct eq5p_match_data eq5p_eyeq5_data = { + .npins = ARRAY_SIZE(eq5p_eyeq5_pins), + .nfunctions = ARRAY_SIZE(eq5p_eyeq5_functions), + .nbanks = ARRAY_SIZE(eq5p_eyeq5_banks), + .pins = eq5p_eyeq5_pins, + .functions = eq5p_eyeq5_functions, + .banks = eq5p_eyeq5_banks, }; static void eq5p_update_bits(const struct eq5p_pinctrl *pctrl, - enum eq5p_bank bank, enum eq5p_regs reg, - u32 mask, u32 val) + const struct eq5p_bank *bank, + enum eq5p_regs reg, u32 mask, u32 val) { - void __iomem *ptr = pctrl->base + eq5p_regs[bank][reg]; + void __iomem *ptr = pctrl->base + bank->regs[reg]; writel((readl(ptr) & ~mask) | (val & mask), ptr); } static bool eq5p_test_bit(const struct eq5p_pinctrl *pctrl, - enum eq5p_bank bank, enum eq5p_regs reg, int offset) + const struct eq5p_bank *bank, + enum eq5p_regs reg, int offset) { - u32 val = readl(pctrl->base + eq5p_regs[bank][reg]); + u32 val = readl(pctrl->base + bank->regs[reg]); if (WARN_ON(offset > 31)) return false; @@ -218,25 +250,29 @@ static bool eq5p_test_bit(const struct eq5p_pinctrl *pctrl, return (val & BIT(offset)) != 0; } -static enum eq5p_bank eq5p_pin_to_bank(unsigned int pin) +static int eq5p_pin_to_bank_offset(const struct eq5p_pinctrl *pctrl, unsigned int pin, + const struct eq5p_bank **bank, unsigned int *offset) { - if (pin < EQ5P_PIN_OFFSET_BANK_B) - return EQ5P_BANK_A; - else - return EQ5P_BANK_B; -} + for (unsigned int i = 0; i < pctrl->data->nbanks; i++) { + const struct eq5p_bank *_bank = &pctrl->data->banks[i]; + unsigned int npins = _bank->npins; -static unsigned int eq5p_pin_to_offset(unsigned int pin) -{ - if (pin < EQ5P_PIN_OFFSET_BANK_B) - return pin; - else - return pin - EQ5P_PIN_OFFSET_BANK_B; + if (pin < npins) { + *bank = _bank; + *offset = pin; + return 0; + } + pin -= npins; + } + + return -EINVAL; } static int eq5p_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) { - return ARRAY_SIZE(eq5p_pins); + struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->data->npins; } static const char *eq5p_pinctrl_get_group_name(struct pinctrl_dev *pctldev, @@ -260,10 +296,15 @@ static int eq5p_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, { enum pin_config_param param = pinconf_to_config_param(*config); struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - unsigned int offset = eq5p_pin_to_offset(pin); - enum eq5p_bank bank = eq5p_pin_to_bank(pin); + const struct eq5p_bank *bank; + unsigned int offset; u32 val_ds, arg; bool pd, pu; + int ret; + + ret = eq5p_pin_to_bank_offset(pctrl, pin, &bank, &offset); + if (ret) + return ret; pd = eq5p_test_bit(pctrl, bank, EQ5P_PD, offset); pu = eq5p_test_bit(pctrl, bank, EQ5P_PU, offset); @@ -281,10 +322,10 @@ static int eq5p_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, case PIN_CONFIG_DRIVE_STRENGTH: offset *= 2; /* two bits per pin */ if (offset >= 32) { - val_ds = readl(pctrl->base + eq5p_regs[bank][EQ5P_DS_HIGH]); + val_ds = readl(pctrl->base + bank->regs[EQ5P_DS_HIGH]); offset -= 32; } else { - val_ds = readl(pctrl->base + eq5p_regs[bank][EQ5P_DS_LOW]); + val_ds = readl(pctrl->base + bank->regs[EQ5P_DS_LOW]); } arg = (val_ds >> offset) & EQ5P_DS_MASK; break; @@ -302,30 +343,35 @@ static void eq5p_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, { struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); const char *pin_name = pctrl->desc.pins[pin].name; - unsigned int offset = eq5p_pin_to_offset(pin); - enum eq5p_bank bank = eq5p_pin_to_bank(pin); + const struct eq5p_bank *bank; const char *func_name, *bias; unsigned long ds_config; + unsigned int offset; u32 drive_strength; bool pd, pu; int i, j; + if (eq5p_pin_to_bank_offset(pctrl, pin, &bank, &offset)) { + seq_puts(s, "unknown pin"); + return; + } + /* * First, let's get the function name. All pins have only two functions: * GPIO (IOCR == 0) and something else (IOCR == 1). */ if (eq5p_test_bit(pctrl, bank, EQ5P_IOCR, offset)) { func_name = NULL; - for (i = 0; i < ARRAY_SIZE(eq5p_functions); i++) { - if (i == GPIO_FUNC_SELECTOR) + for (i = 0; i < pctrl->data->nfunctions; i++) { + if (i == EQ5P_GPIO_FUNC_SELECTOR) continue; - for (j = 0; j < eq5p_functions[i].ngroups; j++) { + for (j = 0; j < pctrl->data->functions[i].ngroups; j++) { /* Groups and pins are the same thing for us. */ - const char *x = eq5p_functions[i].groups[j]; + const char *x = pctrl->data->functions[i].groups[j]; if (strcmp(x, pin_name) == 0) { - func_name = eq5p_functions[i].name; + func_name = pctrl->data->functions[i].name; break; } } @@ -341,7 +387,7 @@ static void eq5p_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, if (!func_name) func_name = "unknown"; } else { - func_name = eq5p_functions[GPIO_FUNC_SELECTOR].name; + func_name = pctrl->data->functions[EQ5P_GPIO_FUNC_SELECTOR].name; } /* Second, we retrieve the bias. */ @@ -376,13 +422,17 @@ static const struct pinctrl_ops eq5p_pinctrl_ops = { static int eq5p_pinmux_get_functions_count(struct pinctrl_dev *pctldev) { - return ARRAY_SIZE(eq5p_functions); + struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->data->nfunctions; } static const char *eq5p_pinmux_get_function_name(struct pinctrl_dev *pctldev, unsigned int selector) { - return eq5p_functions[selector].name; + struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->data->functions[selector].name; } static int eq5p_pinmux_get_function_groups(struct pinctrl_dev *pctldev, @@ -390,8 +440,10 @@ static int eq5p_pinmux_get_function_groups(struct pinctrl_dev *pctldev, const char * const **groups, unsigned int *num_groups) { - *groups = eq5p_functions[selector].groups; - *num_groups = eq5p_functions[selector].ngroups; + struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + *groups = pctrl->data->functions[selector].groups; + *num_groups = pctrl->data->functions[selector].ngroups; return 0; } @@ -399,12 +451,17 @@ static int eq5p_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector, unsigned int pin) { struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - const char *func_name = eq5p_functions[func_selector].name; + const char *func_name = pctrl->data->functions[func_selector].name; const char *group_name = pctldev->desc->pins[pin].name; - bool is_gpio = func_selector == GPIO_FUNC_SELECTOR; - unsigned int offset = eq5p_pin_to_offset(pin); - enum eq5p_bank bank = eq5p_pin_to_bank(pin); + bool is_gpio = func_selector == EQ5P_GPIO_FUNC_SELECTOR; + const struct eq5p_bank *bank; + unsigned int offset; u32 mask, val; + int ret; + + ret = eq5p_pin_to_bank_offset(pctrl, pin, &bank, &offset); + if (ret) + return ret; dev_dbg(pctldev->dev, "func=%s group=%s\n", func_name, group_name); @@ -419,7 +476,7 @@ static int eq5p_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev, unsigned int pin) { /* Pin numbers and group selectors are the same thing in our case. */ - return eq5p_pinmux_set_mux(pctldev, GPIO_FUNC_SELECTOR, pin); + return eq5p_pinmux_set_mux(pctldev, EQ5P_GPIO_FUNC_SELECTOR, pin); } static const struct pinmux_ops eq5p_pinmux_ops = { @@ -435,10 +492,15 @@ static int eq5p_pinconf_set_drive_strength(struct pinctrl_dev *pctldev, unsigned int pin, u32 arg) { struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - unsigned int offset = eq5p_pin_to_offset(pin); - enum eq5p_bank bank = eq5p_pin_to_bank(pin); + const struct eq5p_bank *bank; + unsigned int offset; unsigned int reg; u32 mask, val; + int ret; + + ret = eq5p_pin_to_bank_offset(pctrl, pin, &bank, &offset); + if (ret) + return ret; if (arg & ~EQ5P_DS_MASK) { dev_err(pctldev->dev, "Unsupported drive strength: %u\n", arg); @@ -465,12 +527,18 @@ static int eq5p_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, { struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); const char *pin_name = pctldev->desc->pins[pin].name; - unsigned int offset = eq5p_pin_to_offset(pin); - enum eq5p_bank bank = eq5p_pin_to_bank(pin); struct device *dev = pctldev->dev; - u32 val = BIT(offset); + const struct eq5p_bank *bank; + unsigned int offset; unsigned int i; + u32 val; + int ret; + ret = eq5p_pin_to_bank_offset(pctrl, pin, &bank, &offset); + if (ret) + return ret; + + val = BIT(offset); for (i = 0; i < num_configs; i++) { enum pin_config_param param = pinconf_to_config_param(configs[i]); u32 arg = pinconf_to_config_argument(configs[i]); @@ -533,19 +601,26 @@ static const struct pinconf_ops eq5p_pinconf_ops = { static int eq5p_probe(struct auxiliary_device *adev, const struct auxiliary_device_id *id) { + const struct of_device_id *match; struct device *dev = &adev->dev; struct pinctrl_dev *pctldev; struct eq5p_pinctrl *pctrl; int ret; + /* Get match data based on parent OF node set in clk-eyeq */ + match = of_match_node(dev->driver->of_match_table, dev->of_node); + if (!match || !match->data) + return -ENODEV; + pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL); if (!pctrl) return -ENOMEM; pctrl->base = (void __iomem *)dev_get_platdata(dev); + pctrl->data = match->data; pctrl->desc.name = dev_name(dev); - pctrl->desc.pins = eq5p_pins; - pctrl->desc.npins = ARRAY_SIZE(eq5p_pins); + pctrl->desc.pins = pctrl->data->pins; + pctrl->desc.npins = pctrl->data->npins; pctrl->desc.pctlops = &eq5p_pinctrl_ops; pctrl->desc.pmxops = &eq5p_pinmux_ops; pctrl->desc.confops = &eq5p_pinconf_ops; @@ -562,6 +637,12 @@ static int eq5p_probe(struct auxiliary_device *adev, return 0; } +static const struct of_device_id eq5p_match_table[] = { + { .compatible = "mobileye,eyeq5-olb", .data = &eq5p_eyeq5_data }, + {} +}; +MODULE_DEVICE_TABLE(of, eq5p_match_table); + static const struct auxiliary_device_id eq5p_id_table[] = { { .name = "clk_eyeq.pinctrl" }, {} @@ -571,5 +652,8 @@ MODULE_DEVICE_TABLE(auxiliary, eq5p_id_table); static struct auxiliary_driver eq5p_driver = { .probe = eq5p_probe, .id_table = eq5p_id_table, + .driver = { + .of_match_table = eq5p_match_table, + } }; module_auxiliary_driver(eq5p_driver); From c4fc0fb95ad3771dc2269bc48bdde50c50d48b71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Monin?= Date: Mon, 16 Mar 2026 16:25:43 +0100 Subject: [PATCH 19/30] pinctrl: eyeq5: Add Mobileye EyeQ6Lplus OLB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the match data for the pinctrl found in the EyeQ6Lplus OLB. The pin control is identical in function to the one present in the EyeQ5 but has a single bank of 32 pins. Signed-off-by: Benoît Monin Reviewed-by: Linus Walleij Signed-off-by: Thomas Bogendoerfer --- drivers/pinctrl/Kconfig | 4 +- drivers/pinctrl/pinctrl-eyeq5.c | 95 +++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index afecd9407f53..72c7f21d81e4 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -254,11 +254,11 @@ config PINCTRL_EQUILIBRIUM config PINCTRL_EYEQ5 bool "Mobileye EyeQ5 pinctrl driver" depends on OF - depends on MACH_EYEQ5 || COMPILE_TEST + depends on MACH_EYEQ5 || MACH_EYEQ6LPLUS || COMPILE_TEST select PINMUX select GENERIC_PINCONF select AUXILIARY_BUS - default MACH_EYEQ5 + default MACH_EYEQ5 || MACH_EYEQ6LPLUS help Pin controller driver for the Mobileye EyeQ5 platform. It does both pin config & pin muxing. It does not handle GPIO. diff --git a/drivers/pinctrl/pinctrl-eyeq5.c b/drivers/pinctrl/pinctrl-eyeq5.c index c780af09cde9..dcdf80f07a90 100644 --- a/drivers/pinctrl/pinctrl-eyeq5.c +++ b/drivers/pinctrl/pinctrl-eyeq5.c @@ -229,6 +229,100 @@ static const struct eq5p_match_data eq5p_eyeq5_data = { .banks = eq5p_eyeq5_banks, }; +static const struct pinctrl_pin_desc eq5p_eyeq6lplus_pins[] = { + PINCTRL_PIN(0, "PA0"), /* GPIO_A0_TIMER0_CK0 */ + PINCTRL_PIN(1, "PA1"), /* GPIO_A1_TIMER0_EOC */ + PINCTRL_PIN(2, "PA2"), /* GPIO_A2_TIMER1_CK */ + PINCTRL_PIN(3, "PA3"), /* GPIO_A3_TIMER1_EOC1 */ + PINCTRL_PIN(4, "PA4"), /* GPIO_A4_SSI_UART_RX */ + PINCTRL_PIN(5, "PA5"), /* GPIO_A5_SSI_UART_TX */ + PINCTRL_PIN(6, "PA6"), /* GPIO_A6_SPI_0_CS */ + PINCTRL_PIN(7, "PA7"), /* GPIO_A7_SPI_0_DI */ + PINCTRL_PIN(8, "PA8"), /* GPIO_A8_SPI_0_CK */ + PINCTRL_PIN(9, "PA9"), /* GPIO_A9_SPI_0_DO */ + PINCTRL_PIN(10, "PA10"), /* GPIO_A10_SPI_0_CS1 */ + PINCTRL_PIN(11, "PA11"), /* GPIO_A11_UART_0_RX */ + PINCTRL_PIN(12, "PA12"), /* GPIO_A12_UART_0_TX */ + PINCTRL_PIN(13, "PA13"), /* GPIO_A13_TIMER2_CK */ + PINCTRL_PIN(14, "PA14"), /* GPIO_A14_TIMER2_EOC */ + PINCTRL_PIN(15, "PA15"), /* GPIO_A15_TIMER3_CK */ + PINCTRL_PIN(16, "PA16"), /* GPIO_A16_TIMER_EOC */ + PINCTRL_PIN(17, "PA17"), /* GPIO_A17_TIMER_EXT0_INCA P1 */ + PINCTRL_PIN(18, "PA18"), /* GPIO_A18_TIMER_EXT0_INCA P2 */ + PINCTRL_PIN(19, "PA19"), /* GPIO_A19_TIMER_EXT0_OUT CMP1 */ + PINCTRL_PIN(20, "PA20"), /* GPIO_A20_TIMER_EXT0_OUT CMP2 */ + PINCTRL_PIN(21, "PA21"), /* GPIO_A21_SPI_1_CS0 */ + PINCTRL_PIN(22, "PA22"), /* GPIO_A22_SPI_1_DI */ + PINCTRL_PIN(23, "PA23"), /* GPIO_A23_SPI_1_CK */ + PINCTRL_PIN(24, "PA24"), /* GPIO_A24_SPI_1_DO */ + PINCTRL_PIN(25, "PA25"), /* GPIO_A25_SPI_1_CS1 */ + PINCTRL_PIN(26, "PA26"), /* GPIO_A26_TIMER_EXT1_INCA P1 */ + PINCTRL_PIN(27, "PA27"), /* GPIO_A27_TIMER_EXT1_INCA P2 */ + PINCTRL_PIN(28, "PA28"), /* GPIO_A28_TIMER_EXT1_OUTC MP1 */ + PINCTRL_PIN(29, "PA29"), /* GPIO_A29_TIMER_EXT1_OUTC MP2 */ + PINCTRL_PIN(30, "PA30"), /* GPIO_A30_EXT_CLK */ + PINCTRL_PIN(31, "PA31"), /* GPIO_A31_VDI_MCLK */ +}; + +static const char * const eq5p_eyeq6lplus_gpio_groups[] = { + /* Bank A */ + "PA0", "PA1", "PA2", "PA3", "PA4", "PA5", "PA6", "PA7", + "PA8", "PA9", "PA10", "PA11", "PA12", "PA13", "PA14", "PA15", + "PA16", "PA17", "PA18", "PA19", "PA20", "PA21", "PA22", "PA23", + "PA24", "PA25", "PA26", "PA27", "PA28", "PA29", "PA30", "PA31", +}; + +/* Groups of functions on bank A */ +static const char * const eq5p_eyeq6lplus_timer0_groups[] = { "PA0", "PA1" }; +static const char * const eq5p_eyeq6lplus_timer1_groups[] = { "PA2", "PA3" }; +static const char * const eq5p_eyeq6lplus_uart_ssi_groups[] = { "PA4", "PA5" }; +static const char * const eq5p_eyeq6lplus_spi0_groups[] = { "PA6", "PA7", "PA8", "PA9", "PA10" }; +static const char * const eq5p_eyeq6lplus_uart0_groups[] = { "PA11", "PA12" }; +static const char * const eq5p_eyeq6lplus_timer2_groups[] = { "PA13", "PA14" }; +static const char * const eq5p_eyeq6lplus_timer3_groups[] = { "PA15", "PA16" }; +static const char * const eq5p_eyeq6lplus_timer_ext0_groups[] = { "PA17", "PA18", "PA19", "PA20" }; +static const char * const eq5p_eyeq6lplus_spi1_groups[] = { + "PA21", "PA22", "PA23", "PA24", "PA25" +}; +static const char * const eq5p_eyeq6lplus_timer_ext1_groups[] = { "PA26", "PA27", "PA28", "PA29" }; +static const char * const eq5p_eyeq6lplus_ext_ref_clk_groups[] = { "PA30" }; +static const char * const eq5p_eyeq6lplus_mipi_ref_clk_groups[] = { "PA31" }; + +static const struct pinfunction eq5p_eyeq6lplus_functions[] = { + /* gpios function */ + EQ5P_PINFUNCTION("gpio", eq5p_eyeq6lplus_gpio_groups), + + /* Bank A alternate functions */ + EQ5P_PINFUNCTION("timer0", eq5p_eyeq6lplus_timer0_groups), + EQ5P_PINFUNCTION("timer1", eq5p_eyeq6lplus_timer1_groups), + EQ5P_PINFUNCTION("uart_ssi", eq5p_eyeq6lplus_uart_ssi_groups), + EQ5P_PINFUNCTION("spi0", eq5p_eyeq6lplus_spi0_groups), + EQ5P_PINFUNCTION("uart0", eq5p_eyeq6lplus_uart0_groups), + EQ5P_PINFUNCTION("timer2", eq5p_eyeq6lplus_timer2_groups), + EQ5P_PINFUNCTION("timer3", eq5p_eyeq6lplus_timer3_groups), + EQ5P_PINFUNCTION("timer_ext0", eq5p_eyeq6lplus_timer_ext0_groups), + EQ5P_PINFUNCTION("spi1", eq5p_eyeq6lplus_spi1_groups), + EQ5P_PINFUNCTION("timer_ext1", eq5p_eyeq6lplus_timer_ext1_groups), + EQ5P_PINFUNCTION("ext_ref_clk", eq5p_eyeq6lplus_ext_ref_clk_groups), + EQ5P_PINFUNCTION("mipi_ref_clk", eq5p_eyeq6lplus_mipi_ref_clk_groups), +}; + +static const struct eq5p_bank eq5p_eyeq6lplus_banks[] = { + { + .npins = ARRAY_SIZE(eq5p_eyeq6lplus_pins), + .regs = {0x0C0, 0x0C4, 0x0D0, 0x0D4, 0x0B0}, + }, +}; + +static const struct eq5p_match_data eq5p_eyeq6lplus_data = { + .npins = ARRAY_SIZE(eq5p_eyeq6lplus_pins), + .nfunctions = ARRAY_SIZE(eq5p_eyeq6lplus_functions), + .nbanks = ARRAY_SIZE(eq5p_eyeq6lplus_banks), + .pins = eq5p_eyeq6lplus_pins, + .functions = eq5p_eyeq6lplus_functions, + .banks = eq5p_eyeq6lplus_banks, +}; + static void eq5p_update_bits(const struct eq5p_pinctrl *pctrl, const struct eq5p_bank *bank, enum eq5p_regs reg, u32 mask, u32 val) @@ -639,6 +733,7 @@ static int eq5p_probe(struct auxiliary_device *adev, static const struct of_device_id eq5p_match_table[] = { { .compatible = "mobileye,eyeq5-olb", .data = &eq5p_eyeq5_data }, + { .compatible = "mobileye,eyeq6lplus-olb", .data = &eq5p_eyeq6lplus_data }, {} }; MODULE_DEVICE_TABLE(of, eq5p_match_table); From 8ab1e58ca9eb21d44c4716141248acac1d0635cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Monin?= Date: Mon, 16 Mar 2026 16:25:44 +0100 Subject: [PATCH 20/30] clk: eyeq: Skip post-divisor when computing PLL frequency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The output of the PLL is routed before the post-divisor so it should be ignored when computing the frequency of the PLL, functional change is implemented to reflect how the clock signal is wired internally. For the PLL of the EyeQ5, EyeQ6L, and EyeQ6H, this change has no impact as the post-divisor is either reported as disabled or set to 1. The PLL frequency is the same before and after the post-divisor. For the PLL in EyeQ6Lplus, however, the post-divisor is not 1, so it must be ignored to compute the correct frequency. Signed-off-by: Benoît Monin Acked-by: Stephen Boyd Signed-off-by: Thomas Bogendoerfer --- drivers/clk/clk-eyeq.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/clk/clk-eyeq.c b/drivers/clk/clk-eyeq.c index 81137269352d..5166b65382a9 100644 --- a/drivers/clk/clk-eyeq.c +++ b/drivers/clk/clk-eyeq.c @@ -177,8 +177,6 @@ static int eqc_pll_parse_registers(u32 r0, u32 r1, unsigned long *mult, *mult = FIELD_GET(PCSR0_INTIN, r0); *div = FIELD_GET(PCSR0_REF_DIV, r0); - if (r0 & PCSR0_FOUTPOSTDIV_EN) - *div *= FIELD_GET(PCSR0_POST_DIV1, r0) * FIELD_GET(PCSR0_POST_DIV2, r0); /* Fractional mode, in 2^20 (0x100000) parts. */ if (r0 & PCSR0_DSM_EN) { From fe9545bbc3c6befce2b72b53cdf12004193e63e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Monin?= Date: Mon, 16 Mar 2026 16:25:45 +0100 Subject: [PATCH 21/30] clk: eyeq: Adjust PLL accuracy computation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The spread spectrum of the PLL found in eyeQ OLB is in 1/1024 parts of the frequency, not in 1/1000, so adjust the computation of the accuracy. Also correct the downspreading to match. Signed-off-by: Benoît Monin Acked-by: Stephen Boyd Signed-off-by: Thomas Bogendoerfer --- drivers/clk/clk-eyeq.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/clk/clk-eyeq.c b/drivers/clk/clk-eyeq.c index 5166b65382a9..11df9f167b59 100644 --- a/drivers/clk/clk-eyeq.c +++ b/drivers/clk/clk-eyeq.c @@ -163,7 +163,7 @@ static void eqc_pll_downshift_factors(unsigned long *mult, unsigned long *div) static int eqc_pll_parse_registers(u32 r0, u32 r1, unsigned long *mult, unsigned long *div, unsigned long *acc) { - u32 spread; + unsigned long spread; if (r0 & PCSR0_BYPASS) { *mult = 1; @@ -195,23 +195,23 @@ static int eqc_pll_parse_registers(u32 r0, u32 r1, unsigned long *mult, /* * Spread spectrum. * - * Spread is 1/1000 parts of frequency, accuracy is half of - * that. To get accuracy, convert to ppb (parts per billion). + * Spread is in 1/1024 parts of frequency. Clock accuracy + * is half the spread value expressed in parts per billion. * - * acc = spread * 1e6 / 2 - * with acc in parts per billion and, - * spread in parts per thousand. + * accuracy = (spread * 1e9) / (1024 * 2) + * + * Care is taken to avoid overflowing or losing precision. */ spread = FIELD_GET(PCSR1_SPREAD, r1); - *acc = spread * 500000; + *acc = DIV_ROUND_CLOSEST(spread * 1000000000, 1024 * 2); if (r1 & PCSR1_DOWN_SPREAD) { /* * Downspreading: the central frequency is half a * spread lower. */ - *mult *= 2000 - spread; - *div *= 2000; + *mult *= 2048 - spread; + *div *= 2048; /* * Previous operation might overflow 32 bits. If it From 4eb9ed3933e541ed96416608033620f64eea39f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Monin?= Date: Mon, 16 Mar 2026 16:25:46 +0100 Subject: [PATCH 22/30] clk: eyeq: Add Mobileye EyeQ6Lplus OLB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Declare the PLLs and fixed factors found in the EyeQ6Lplus OLB as part of the match data for the "mobileye,eyeq6lplus-olb" compatible. The PLL and fixed factor of the CPU are registered in early init as they are required during the boot by the GIC timer. Also select clk-eyeq for all EYEQ SoCs instead of listing each one individually, as it is needed by all Mobileye EyeQ SoC. Signed-off-by: Benoît Monin Acked-by: Stephen Boyd Signed-off-by: Thomas Bogendoerfer --- drivers/clk/Kconfig | 4 +-- drivers/clk/clk-eyeq.c | 70 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 3d803b4cf5c1..240e9dbeff2b 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -236,9 +236,9 @@ config COMMON_CLK_EP93XX config COMMON_CLK_EYEQ bool "Clock driver for the Mobileye EyeQ platform" - depends on MACH_EYEQ5 || MACH_EYEQ6H || COMPILE_TEST + depends on EYEQ || COMPILE_TEST select AUXILIARY_BUS - default MACH_EYEQ5 || MACH_EYEQ6H + default EYEQ help This driver provides clocks found on Mobileye EyeQ5, EyeQ6L and Eye6H SoCs. Controllers live in shared register regions called OLB. Driver diff --git a/drivers/clk/clk-eyeq.c b/drivers/clk/clk-eyeq.c index 11df9f167b59..c1dccedf8d5b 100644 --- a/drivers/clk/clk-eyeq.c +++ b/drivers/clk/clk-eyeq.c @@ -45,6 +45,7 @@ #include #include +#include /* In frac mode, it enables fractional noise canceling DAC. Else, no function. */ #define PCSR0_DAC_EN BIT(0) @@ -571,6 +572,68 @@ static const struct eqc_match_data eqc_eyeq6l_match_data = { .reset_auxdev_name = "reset", }; +static const struct eqc_pll eqc_eyeq6lplus_early_plls[] = { + { .index = EQ6LPC_PLL_CPU, .name = "pll-cpu", .reg64 = 0x058 }, +}; + +static const struct eqc_pll eqc_eyeq6lplus_plls[] = { + { .index = EQ6LPC_PLL_DDR, .name = "pll-ddr", .reg64 = 0x02C }, + { .index = EQ6LPC_PLL_ACC, .name = "pll-acc", .reg64 = 0x034 }, + { .index = EQ6LPC_PLL_PER, .name = "pll-per", .reg64 = 0x03C }, + { .index = EQ6LPC_PLL_VDI, .name = "pll-vdi", .reg64 = 0x044 }, +}; + +static const struct eqc_fixed_factor eqc_eyeq6lplus_early_fixed_factors[] = { + { EQ6LPC_CPU_OCC, "occ-cpu", 1, 1, EQ6LPC_PLL_CPU }, +}; + +static const struct eqc_fixed_factor eqc_eyeq6lplus_fixed_factors[] = { + { EQ6LPC_DDR_OCC, "occ-ddr", 1, 1, EQ6LPC_PLL_DDR }, + + { EQ6LPC_ACC_VDI, "vdi-div", 1, 10, EQ6LPC_PLL_ACC }, + { EQ6LPC_ACC_OCC, "occ-acc", 1, 1, EQ6LPC_PLL_ACC }, + { EQ6LPC_ACC_FCMU, "fcmu-a-clk", 1, 10, EQ6LPC_ACC_OCC }, + + { EQ6LPC_PER_OCC, "occ-per", 1, 1, EQ6LPC_PLL_PER }, + { EQ6LPC_PER_I2C_SER, "i2c-ser-clk", 1, 10, EQ6LPC_PER_OCC }, + { EQ6LPC_PER_PCLK, "pclk", 1, 4, EQ6LPC_PER_OCC }, + { EQ6LPC_PER_TSU, "tsu-clk", 1, 8, EQ6LPC_PER_OCC }, + { EQ6LPC_PER_OSPI, "ospi-ref-clk", 1, 10, EQ6LPC_PER_OCC }, + { EQ6LPC_PER_GPIO, "gpio-clk", 1, 4, EQ6LPC_PER_OCC }, + { EQ6LPC_PER_TIMER, "timer-clk", 1, 4, EQ6LPC_PER_OCC }, + { EQ6LPC_PER_I2C, "i2c-clk", 1, 4, EQ6LPC_PER_OCC }, + { EQ6LPC_PER_UART, "uart-clk", 1, 4, EQ6LPC_PER_OCC }, + { EQ6LPC_PER_SPI, "spi-clk", 1, 4, EQ6LPC_PER_OCC }, + { EQ6LPC_PER_PERIPH, "periph-clk", 1, 1, EQ6LPC_PER_OCC }, + + { EQ6LPC_VDI_OCC, "occ-vdi", 1, 1, EQ6LPC_PLL_VDI }, +}; + +static const struct eqc_early_match_data eqc_eyeq6lplus_early_match_data __initconst = { + .early_pll_count = ARRAY_SIZE(eqc_eyeq6lplus_early_plls), + .early_plls = eqc_eyeq6lplus_early_plls, + + .early_fixed_factor_count = ARRAY_SIZE(eqc_eyeq6lplus_early_fixed_factors), + .early_fixed_factors = eqc_eyeq6lplus_early_fixed_factors, + + .late_clk_count = ARRAY_SIZE(eqc_eyeq6lplus_plls) + + ARRAY_SIZE(eqc_eyeq6lplus_fixed_factors), +}; + +static const struct eqc_match_data eqc_eyeq6lplus_match_data = { + .pll_count = ARRAY_SIZE(eqc_eyeq6lplus_plls), + .plls = eqc_eyeq6lplus_plls, + + .fixed_factor_count = ARRAY_SIZE(eqc_eyeq6lplus_fixed_factors), + .fixed_factors = eqc_eyeq6lplus_fixed_factors, + + .reset_auxdev_name = "reset", + .pinctrl_auxdev_name = "pinctrl", + + .early_clk_count = ARRAY_SIZE(eqc_eyeq6lplus_early_plls) + + ARRAY_SIZE(eqc_eyeq6lplus_early_fixed_factors), +}; + static const struct eqc_match_data eqc_eyeq6h_west_match_data = { .reset_auxdev_name = "reset_west", }; @@ -672,6 +735,7 @@ static const struct eqc_match_data eqc_eyeq6h_acc_match_data = { static const struct of_device_id eqc_match_table[] = { { .compatible = "mobileye,eyeq5-olb", .data = &eqc_eyeq5_match_data }, { .compatible = "mobileye,eyeq6l-olb", .data = &eqc_eyeq6l_match_data }, + { .compatible = "mobileye,eyeq6lplus-olb", .data = &eqc_eyeq6lplus_match_data }, { .compatible = "mobileye,eyeq6h-west-olb", .data = &eqc_eyeq6h_west_match_data }, { .compatible = "mobileye,eyeq6h-east-olb", .data = &eqc_eyeq6h_east_match_data }, { .compatible = "mobileye,eyeq6h-south-olb", .data = &eqc_eyeq6h_south_match_data }, @@ -855,3 +919,9 @@ static void __init eqc_eyeq6h_west_early_init(struct device_node *np) } CLK_OF_DECLARE_DRIVER(eqc_eyeq6h_west, "mobileye,eyeq6h-west-olb", eqc_eyeq6h_west_early_init); + +static void __init eqc_eyeq6lplus_early_init(struct device_node *np) +{ + eqc_early_init(np, &eqc_eyeq6lplus_early_match_data); +} +CLK_OF_DECLARE_DRIVER(eqc_eyeq6lplus, "mobileye,eyeq6lplus-olb", eqc_eyeq6lplus_early_init); From 361600d16e3aba997ec5fa482732565580a948b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Monin?= Date: Mon, 16 Mar 2026 16:25:47 +0100 Subject: [PATCH 23/30] MIPS: Add Mobileye EyeQ6Lplus SoC dtsi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the device tree include files for the EyeQ6Lplus system on chip from Mobileye. Those files provide the initial support of the SoC: * The I6500 CPU and GIC interrupt controller. * The OLB ("Other Logic Block") providing clocks, resets and pin controls. * One UART. * One GPIO controller. * Two SPI controllers, one in host mode and one in target mode. * One octoSPI flash controller. * Two I2C controllers. Signed-off-by: Benoît Monin Signed-off-by: Thomas Bogendoerfer --- .../boot/dts/mobileye/eyeq6lplus-pins.dtsi | 84 +++++++++ arch/mips/boot/dts/mobileye/eyeq6lplus.dtsi | 170 ++++++++++++++++++ 2 files changed, 254 insertions(+) create mode 100644 arch/mips/boot/dts/mobileye/eyeq6lplus-pins.dtsi create mode 100644 arch/mips/boot/dts/mobileye/eyeq6lplus.dtsi diff --git a/arch/mips/boot/dts/mobileye/eyeq6lplus-pins.dtsi b/arch/mips/boot/dts/mobileye/eyeq6lplus-pins.dtsi new file mode 100644 index 000000000000..5cb0660f46c6 --- /dev/null +++ b/arch/mips/boot/dts/mobileye/eyeq6lplus-pins.dtsi @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + +&olb { + timer0_pins: timer0-pins { + function = "timer0"; + pins = "PA0", "PA1"; + }; + timer1_pins: timer1-pins { + function = "timer1"; + pins = "PA2", "PA3"; + }; + uart_ssi_pins: uart-ssi-pins { + function = "uart_ssi"; + pins = "PA4", "PA5"; + }; + spi0_pins: spi0-pins { + function = "spi0"; + pins = "PA6", "PA7", "PA8", "PA9"; + }; + uart0_pins: uart0-pins { + function = "uart0"; + pins = "PA11", "PA12"; + }; + timer2_pins: timer2-pins { + function = "timer2"; + pins = "PA13", "PA14"; + }; + timer3_pins: timer3-pins { + function = "timer3"; + pins = "PA15", "PA16"; + }; + timer_ext0_pins: timer-ext0-pins { + function = "timer_ext0"; + pins = "PA17", "PA18", "PA19", "PA20"; + }; + timer_ext0_input_a_pins: timer-ext0-input-a-pins { + function = "timer_ext0"; + pins = "PA17"; + }; + pps0_pins: pps0-pins { + function = "timer_ext0"; + pins = "PA17"; + }; + timer_ext0_input_b_pins: timer-ext0-input-b-pins { + function = "timer_ext0"; + pins = "PA18"; + }; + timer_ext0_output_pins: timer-ext0-output-pins { + function = "timer_ext0"; + pins = "PA19", "PA20"; + }; + spi1_pins: spi1-pins { + function = "spi1"; + pins = "PA21", "PA22", "PA23", "PA24"; + }; + spi1_reduced_pins: spi1-reduced-pins { + function = "spi1"; + pins = "PA21", "PA22", "PA23"; + }; + timer_ext1_pins: timer-ext1-pins { + function = "timer_ext1"; + pins = "PA26", "PA27", "PA28", "PA29"; + }; + timer_ext1_input_a_pins: timer-ext1-input-a-pins { + function = "timer_ext1"; + pins = "PA26"; + }; + timer_ext1_input_b_pins: timer-ext1-input-b-pins { + function = "timer_ext1"; + pins = "PA27"; + }; + timer_ext1_output_pins: timer-ext1-output-pins { + function = "timer_ext1"; + pins = "PA28", "PA29"; + }; + ext_ref_clk_pins: ext-ref-clk-pins { + function = "ext_ref_clk"; + pins = "PA30"; + }; + mipi_ref_clk_pins: mipi-ref-clk-pins { + function = "mipi_ref_clk"; + pins = "PA31"; + }; +}; diff --git a/arch/mips/boot/dts/mobileye/eyeq6lplus.dtsi b/arch/mips/boot/dts/mobileye/eyeq6lplus.dtsi new file mode 100644 index 000000000000..4c72da917a95 --- /dev/null +++ b/arch/mips/boot/dts/mobileye/eyeq6lplus.dtsi @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +/* + * Copyright 2025 Mobileye Vision Technologies Ltd. + */ + +#include + +#include + +/ { + #address-cells = <2>; + #size-cells = <2>; + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu@0 { + device_type = "cpu"; + compatible = "img,i6500"; + reg = <0>; + clocks = <&olb EQ6LPC_CPU_OCC>; + }; + }; + + cpu_intc: interrupt-controller { + compatible = "mti,cpu-interrupt-controller"; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + + coherency-manager { + compatible = "mobileye,eyeq6-cm"; + }; + + xtal: clock-30000000 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <30000000>; + }; + + soc: soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + olb: system-controller@e8400000 { + compatible = "mobileye,eyeq6lplus-olb", "syscon"; + reg = <0 0xe8400000 0x0 0x80000>; + #reset-cells = <2>; + #clock-cells = <1>; + clocks = <&xtal>; + clock-names = "ref"; + }; + + ospi: spi@e8800000 { + compatible = "mobileye,eyeq5-ospi", "cdns,qspi-nor"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0 0xe8800000 0x0 0x100000>, + <0 0xb0000000 0x0 0x30000000>; + interrupt-parent = <&gic>; + interrupts = ; + cdns,fifo-depth = <128>; + cdns,fifo-width = <4>; + cdns,trigger-address = <0x00000000>; + clocks = <&olb EQ6LPC_PER_OSPI>; + status = "disabled"; + }; + + spi0: spi@eac0d000 { + compatible = "snps,dw-apb-ssi"; + reg = <0 0xeac0d000 0x0 0x1000>; + clocks = <&olb EQ6LPC_PER_SPI>; + interrupt-parent = <&gic>; + interrupts = ; + resets = <&olb 0 0>; + reset-names = "spi"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi1: spi@eac0e000 { + compatible = "snps,dw-apb-ssi"; + reg = <0 0xeac0e000 0x0 0x1000>; + spi-slave; + clocks = <&olb EQ6LPC_PER_SPI>; + interrupt-parent = <&gic>; + interrupts = ; + resets = <&olb 0 1>; + reset-names = "spi"; + #address-cells = <0>; + #size-cells = <0>; + status = "disabled"; + }; + + uart0: serial@eac10000 { + compatible = "snps,dw-apb-uart"; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&olb EQ6LPC_PER_UART>; + clock-frequency = <15625000>; + reg = <0 0xeac10000 0x0 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; + resets = <&olb 0 2>; + status = "disabled"; + }; + + i2c0: i2c@eac11000 { + compatible = "mobileye,eyeq6lplus-i2c", "snps,designware-i2c"; + reg = <0 0xeac11000 0x0 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; + clock-frequency = <400000>; + clocks = <&olb EQ6LPC_PER_I2C_SER>; + resets = <&olb 0 3>; + i2c-sda-hold-time-ns = <50>; + status = "disabled"; + }; + + i2c1: i2c@eac12000 { + compatible = "mobileye,eyeq6lplus-i2c", "snps,designware-i2c"; + reg = <0 0xeac12000 0x0 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; + clock-frequency = <400000>; + clocks = <&olb EQ6LPC_PER_I2C_SER>; + resets = <&olb 0 4>; + i2c-sda-hold-time-ns = <50>; + status = "disabled"; + }; + + gpio: gpio@eac14000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x0 0xeac14000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + resets = <&olb 0 13>; + porta: gpio-port@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <32>; + gpio-ranges = <&olb 0 0 32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = ; + }; + }; + + gic: interrupt-controller@f0920000 { + compatible = "mti,gic"; + reg = <0x0 0xf0920000 0x0 0x20000>; + interrupt-controller; + #interrupt-cells = <3>; + interrupt-parent = <&cpu_intc>; + timer { + compatible = "mti,gic-timer"; + interrupts = ; + clocks = <&olb EQ6LPC_CPU_OCC>; + }; + }; + }; +}; + +#include "eyeq6lplus-pins.dtsi" From d024ba24ee6573da93eaa556d467828c5c7defd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Monin?= Date: Mon, 16 Mar 2026 16:25:48 +0100 Subject: [PATCH 24/30] MIPS: Add Mobileye EyeQ6Lplus evaluation board dts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the device tree of the evaluation board of the EyeQ6Lplus SoC. The board comes with 2GB of RAM and an SPI NAND connected to the octoSPI controller The UART of the SoC is used as the serial console. Signed-off-by: Benoît Monin Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/mobileye/Makefile | 1 + .../boot/dts/mobileye/eyeq6lplus-epm6.dts | 103 ++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 arch/mips/boot/dts/mobileye/eyeq6lplus-epm6.dts diff --git a/arch/mips/boot/dts/mobileye/Makefile b/arch/mips/boot/dts/mobileye/Makefile index 7cc89968aaac..9305dd01f4c8 100644 --- a/arch/mips/boot/dts/mobileye/Makefile +++ b/arch/mips/boot/dts/mobileye/Makefile @@ -3,3 +3,4 @@ dtb-$(CONFIG_MACH_EYEQ5) += eyeq5-epm5.dtb dtb-$(CONFIG_MACH_EYEQ6H) += eyeq6h-epm6.dtb +dtb-$(CONFIG_MACH_EYEQ6LPLUS) += eyeq6lplus-epm6.dtb diff --git a/arch/mips/boot/dts/mobileye/eyeq6lplus-epm6.dts b/arch/mips/boot/dts/mobileye/eyeq6lplus-epm6.dts new file mode 100644 index 000000000000..404d0ff09f5a --- /dev/null +++ b/arch/mips/boot/dts/mobileye/eyeq6lplus-epm6.dts @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Copyright 2025 Mobileye Vision Technologies Ltd. + */ + +/dts-v1/; + +#include "eyeq6lplus.dtsi" + +/ { + compatible = "mobileye,eyeq6lplus-epm6", "mobileye,eyeq6lplus"; + model = "Mobileye EyeQ6Lplus Evaluation board"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:921600n8"; + }; + + memory@0 { + device_type = "memory"; + reg = <0x1 0x00000000 0x0 0x80000000>; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* These reserved memory regions are also defined in bootmanager + * for configuring inbound translation for BARS, don't change + * these without syncing with bootmanager + */ + mhm_reserved_0: the-mhm-reserved-0 { + reg = <0x1 0x00000000 0x0 0x0000800>; + }; + bm_logs_reserved: bm-logs-reserved { + reg = <0x1 0x0000800 0x0 0x000f800>; + }; + shmem0_reserved: shmem@804000000 { + reg = <0x1 0x04000000 0x0 0x1000000>; + }; + shmem1_reserved: shmem@805000000 { + reg = <0x1 0x05000000 0x0 0x1000000>; + }; + mini_coredump0_reserved: mini-coredump0@806200000 { + reg = <0x1 0x06200000 0x0 0x100000>; + }; + mailbox_reserved: mailbox-reserved { + reg = <0x1 0x06300000 0x0 0x000300>; + }; + sys_logs_reserved: sys-logs-reserved { + reg = <0x1 0x10000000 0x0 0x800000>; + }; + csl_policy_logs_reserved: csl-policy-logs-reserved { + reg = <0x1 0x10800000 0x0 0x10000>; + }; + }; +}; + +&ospi { + status = "okay"; + flash@0 { + compatible = "spi-nand"; + reg = <0>; + spi-max-frequency = <40000000>; + cdns,read-delay = <0>; + cdns,tshsl-ns = <400>; + cdns,tsd2d-ns = <120>; + cdns,tchsh-ns = <40>; + cdns,tslch-ns = <20>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <8>; + }; +}; + +&spi0 { + pinctrl-0 = <&spi0_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&spi1 { + pinctrl-0 = <&spi1_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&uart0 { + pinctrl-0 = <&uart0_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&i2c0 { + status = "okay"; +}; + +&i2c1 { + status = "okay"; +}; From 9f861f60475dba9f42229f32920f4cdd6b290a5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Monin?= Date: Mon, 16 Mar 2026 16:25:49 +0100 Subject: [PATCH 25/30] MIPS: config: add eyeq6lplus_defconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a default configuration for Mobileye EyeQ6Lplus evaluation board. Signed-off-by: Benoît Monin Signed-off-by: Thomas Bogendoerfer --- arch/mips/configs/eyeq6lplus_defconfig | 117 +++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 arch/mips/configs/eyeq6lplus_defconfig diff --git a/arch/mips/configs/eyeq6lplus_defconfig b/arch/mips/configs/eyeq6lplus_defconfig new file mode 100644 index 000000000000..39430ebf8e60 --- /dev/null +++ b/arch/mips/configs/eyeq6lplus_defconfig @@ -0,0 +1,117 @@ +CONFIG_SYSVIPC=y +CONFIG_NO_HZ_IDLE=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BPF_SYSCALL=y +CONFIG_TASKSTATS=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_MEMCG=y +CONFIG_BLK_CGROUP=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y +CONFIG_EYEQ=y +CONFIG_MACH_EYEQ6LPLUS=y +CONFIG_MIPS_CPS=y +CONFIG_CPU_HAS_MSA=y +CONFIG_NR_CPUS=16 +CONFIG_MIPS_RAW_APPENDED_DTB=y +CONFIG_JUMP_LABEL=y +CONFIG_PAGE_SIZE_16KB=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_TRIM_UNUSED_KSYMS=y +# CONFIG_COMPAT_BRK is not set +CONFIG_USERFAULTFD=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_NETFILTER=y +CONFIG_CAN=y +CONFIG_PCI=y +CONFIG_PCI_MSI=y +CONFIG_PCI_DEBUG=y +CONFIG_PCI_ENDPOINT=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_CONNECTOR=y +CONFIG_MTD=y +CONFIG_MTD_SPI_NAND=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_BLOCK=y +CONFIG_SCSI=y +CONFIG_NETDEVICES=y +CONFIG_MACVLAN=y +CONFIG_IPVLAN=y +CONFIG_MACB=y +CONFIG_MARVELL_PHY=y +CONFIG_MICREL_PHY=y +CONFIG_CAN_M_CAN=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DW=y +CONFIG_HW_RANDOM=y +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_DESIGNWARE_CORE=y +CONFIG_SPI=y +CONFIG_SPI_CADENCE_QUADSPI=y +CONFIG_SPI_DESIGNWARE=y +CONFIG_SPI_DW_MMIO=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPI_SLAVE=y +# CONFIG_PTP_1588_CLOCK is not set +CONFIG_PINCTRL=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_DWAPB=y +CONFIG_MFD_SYSCON=y +CONFIG_HID_A4TECH=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_EZKEY=y +CONFIG_HID_ITE=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_REDRAGON=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_CADENCE=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_RESET_CONTROLLER=y +# CONFIG_NVMEM is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_FS_ENCRYPTION=y +CONFIG_FUSE_FS=y +CONFIG_CUSE=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_UBIFS_FS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_2=y +CONFIG_ROOT_NFS=y +CONFIG_FRAME_WARN=1024 +CONFIG_DEBUG_FS=y +# CONFIG_RCU_TRACE is not set +# CONFIG_FTRACE is not set From 5152a7d4166563e5492c5d1bec3a554002120f7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Monin?= Date: Mon, 16 Mar 2026 16:25:50 +0100 Subject: [PATCH 26/30] MAINTAINERS: Mobileye: Add EyeQ6Lplus files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use wildcard to match all EyeQ defconfigs under arch/mips. This covers the newly added defconfig, and the EyeQ5 and EyeQ6H ones. Add an entry for the dt-bindings header of the EyeQ6Lplus clocks. While at it, add myself to the maintainers of Mobileye MIPS SoCs. Signed-off-by: Benoît Monin Signed-off-by: Thomas Bogendoerfer --- MAINTAINERS | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index c3fe46d7c4bc..7b9b1a76a67b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17800,6 +17800,7 @@ F: drivers/media/dvb-frontends/mn88473* MOBILEYE MIPS SOCS M: Vladimir Kondratiev +M: Benoît Monin M: Gregory CLEMENT M: Théo Lebrun L: linux-mips@vger.kernel.org @@ -17807,12 +17808,13 @@ S: Maintained F: Documentation/devicetree/bindings/mips/mobileye.yaml F: Documentation/devicetree/bindings/soc/mobileye/ F: arch/mips/boot/dts/mobileye/ -F: arch/mips/configs/eyeq5_defconfig +F: arch/mips/configs/eyeq*_defconfig F: arch/mips/mobileye/board-epm5.its.S F: drivers/clk/clk-eyeq.c F: drivers/pinctrl/pinctrl-eyeq5.c F: drivers/reset/reset-eyeq.c F: include/dt-bindings/clock/mobileye,eyeq5-clk.h +F: include/dt-bindings/clock/mobileye,eyeq6lplus-clk.h MODULE SUPPORT M: Luis Chamberlain From d1d0aa620a0f5fc621e5fb780e55a71962b19413 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 20 Mar 2026 21:28:08 +0100 Subject: [PATCH 27/30] MIPS: Alchemy: Remove unused forward declaration The 'struct gpio' is not used in the code, remove unneeded forward declaration. This seems to be a leftover for a 5 years. Acked-by: Thomas Bogendoerfer Signed-off-by: Andy Shevchenko Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/mach-au1x00/gpio-au1000.h | 2 -- arch/mips/include/asm/mach-au1x00/gpio-au1300.h | 1 - 2 files changed, 3 deletions(-) diff --git a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h index d820b481ac56..e6306f6820e6 100644 --- a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h +++ b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h @@ -40,8 +40,6 @@ #define AU1000_GPIO2_INTENABLE 0x10 #define AU1000_GPIO2_ENABLE 0x14 -struct gpio; - static inline int au1000_gpio1_to_irq(int gpio) { return MAKE_IRQ(1, gpio - ALCHEMY_GPIO1_BASE); diff --git a/arch/mips/include/asm/mach-au1x00/gpio-au1300.h b/arch/mips/include/asm/mach-au1x00/gpio-au1300.h index 43d44f384f97..b12f37262cfa 100644 --- a/arch/mips/include/asm/mach-au1x00/gpio-au1300.h +++ b/arch/mips/include/asm/mach-au1x00/gpio-au1300.h @@ -12,7 +12,6 @@ #include #include -struct gpio; struct gpio_chip; /* with the current GPIC design, up to 128 GPIOs are possible. From f992846d0b45691a02d0a9775c5c2a50956e62a5 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Tue, 7 Apr 2026 09:57:03 +0800 Subject: [PATCH 28/30] MIPS: validate DT bootargs before appending them bootcmdline_scan_chosen() fetches the raw flat-DT bootargs property and passes it straight to bootcmdline_append(). That helper later feeds the same pointer into strlcat(), which computes strlen(src) before copying. Flat DT properties are external boot input, and this path does not prove that bootargs is NUL-terminated within its declared bounds. Reject unterminated bootargs properties before appending them to the kernel command line. Signed-off-by: Pengpeng Hou Signed-off-by: Thomas Bogendoerfer --- arch/mips/kernel/setup.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index f9b228e33f3b..1ae6d0c0e1d6 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -541,6 +542,9 @@ static int __init bootcmdline_scan_chosen(unsigned long node, const char *uname, p = of_get_flat_dt_prop(node, "bootargs", &l); if (p != NULL && l > 0) { + if (strnlen(p, l) >= l) + return 1; + bootcmdline_append(p, min(l, COMMAND_LINE_SIZE)); *dt_bootargs = true; } From 42671e9c1e40032f982d2163ba4867dc85e23832 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 28 Mar 2026 16:55:47 +0100 Subject: [PATCH 29/30] MIPS/input: Move RB532 button to GPIO descriptors Convert the Mikrotik RouterBoard RB532 to use GPIO descriptors by defining a software node for the GPIO chip, then register the button platform device with full info passing the GPIO as a device property. This can be used as a base to move more of the RB532 devices over to passing GPIOs using device properties. Use the GPIO_ACTIVE_LOW flag and drop the inversion in the rb532_button_pressed() function. Signed-off-by: Linus Walleij Acked-by: Dmitry Torokhov Signed-off-by: Thomas Bogendoerfer --- arch/mips/rb532/devices.c | 47 ++++++++++++++++++++++++++----- drivers/input/misc/rb532_button.c | 35 +++++++++++++++++++---- 2 files changed, 69 insertions(+), 13 deletions(-) diff --git a/arch/mips/rb532/devices.c b/arch/mips/rb532/devices.c index 4f027efbf27b..3f56d9feb73a 100644 --- a/arch/mips/rb532/devices.c +++ b/arch/mips/rb532/devices.c @@ -16,8 +16,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -38,6 +40,10 @@ extern unsigned int idt_cpu_freq; static struct mpmc_device dev3; +static const struct software_node rb532_gpio0_node = { + .name = "gpio0", +}; + void set_latch_u5(unsigned char or_mask, unsigned char nand_mask) { unsigned long flags; @@ -189,11 +195,6 @@ static struct platform_device rb532_led = { .id = -1, }; -static struct platform_device rb532_button = { - .name = "rb532-button", - .id = -1, -}; - static struct resource rb532_wdt_res[] = { { .name = "rb532_wdt_res", @@ -236,11 +237,23 @@ static struct platform_device *rb532_devs[] = { &nand_slot0, &cf_slot0, &rb532_led, - &rb532_button, &rb532_uart, &rb532_wdt }; +static const struct property_entry rb532_button_properties[] = { + PROPERTY_ENTRY_GPIO("button-gpios", &rb532_gpio0_node, + GPIO_BTN_S1, GPIO_ACTIVE_LOW), + { } +}; + +static const struct platform_device_info rb532_button_info __initconst = { + .name = "rb532-button", + .id = PLATFORM_DEVID_NONE, + .properties = rb532_button_properties, +}; + + /* NAND definitions */ #define NAND_CHIP_DELAY 25 @@ -267,6 +280,9 @@ static void __init rb532_nand_setup(void) static int __init plat_setup_devices(void) { + struct platform_device *pd; + int ret; + /* Look for the CF card reader */ if (!readl(IDT434_REG_BASE + DEV1MASK)) rb532_devs[2] = NULL; /* disable cf_slot0 at index 2 */ @@ -295,7 +311,24 @@ static int __init plat_setup_devices(void) rb532_uart_res[0].uartclk = idt_cpu_freq; gpiod_add_lookup_table(&cf_slot0_gpio_table); - return platform_add_devices(rb532_devs, ARRAY_SIZE(rb532_devs)); + ret = platform_add_devices(rb532_devs, ARRAY_SIZE(rb532_devs)); + if (ret) + return ret; + + /* + * Stack devices using full info and properties here, after we + * register the node for the GPIO chip. + */ + software_node_register(&rb532_gpio0_node); + + pd = platform_device_register_full(&rb532_button_info); + ret = PTR_ERR_OR_ZERO(pd); + if (ret) { + pr_err("failed to create RB532 button device: %d\n", ret); + return ret; + } + + return 0; } #ifdef CONFIG_NET diff --git a/drivers/input/misc/rb532_button.c b/drivers/input/misc/rb532_button.c index 190a80e1e2c1..40173bf7a235 100644 --- a/drivers/input/misc/rb532_button.c +++ b/drivers/input/misc/rb532_button.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include @@ -18,6 +18,14 @@ #define RB532_BTN_RATE 100 /* msec */ #define RB532_BTN_KSYM BTN_0 +/** + * struct rb532_button - RB532 button information + * @gpio: GPIO connected to the button + */ +struct rb532_button { + struct gpio_desc *gpio; +}; + /* The S1 button state is provided by GPIO pin 1. But as this * pin is also used for uart input as alternate function, the * operational modes must be switched first: @@ -31,35 +39,48 @@ * The GPIO value occurs to be inverted, so pin high means * button is not pressed. */ -static bool rb532_button_pressed(void) +static bool rb532_button_pressed(struct rb532_button *button) { int val; set_latch_u5(0, LO_FOFF); - gpio_direction_input(GPIO_BTN_S1); + gpiod_direction_input(button->gpio); - val = gpio_get_value(GPIO_BTN_S1); + val = gpiod_get_value(button->gpio); rb532_gpio_set_func(GPIO_BTN_S1); set_latch_u5(LO_FOFF, 0); - return !val; + return val; } static void rb532_button_poll(struct input_dev *input) { - input_report_key(input, RB532_BTN_KSYM, rb532_button_pressed()); + struct rb532_button *button = input_get_drvdata(input); + + input_report_key(input, RB532_BTN_KSYM, rb532_button_pressed(button)); input_sync(input); } static int rb532_button_probe(struct platform_device *pdev) { + struct rb532_button *button; struct input_dev *input; int error; + button = devm_kzalloc(&pdev->dev, sizeof(*button), GFP_KERNEL); + if (!button) + return -ENOMEM; + + button->gpio = devm_gpiod_get(&pdev->dev, "button", GPIOD_IN); + if (IS_ERR(button->gpio)) + return dev_err_probe(&pdev->dev, PTR_ERR(button->gpio), + "error getting button GPIO\n"); + input = devm_input_allocate_device(&pdev->dev); if (!input) return -ENOMEM; + input_set_drvdata(input, button); input->name = "rb532 button"; input->phys = "rb532/button0"; @@ -77,6 +98,8 @@ static int rb532_button_probe(struct platform_device *pdev) if (error) return error; + platform_set_drvdata(pdev, button); + return 0; } From 15513eefac7ca68602e9de9853f5e671bf7b4eef Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 28 Mar 2026 16:55:48 +0100 Subject: [PATCH 30/30] MIPS/mtd: Handle READY GPIO in generic NAND platform data The callbacks into the MIPS RB532 platform to read the GPIO pin indicating that the NAND chip is ready are oldschool and does not assign GPIOs as properties to the NAND device. Add a capability to the generic platform NAND chip driver to use a GPIO line to detect if a NAND chip is ready and override the platform-local drv_ready() callback with this check if the GPIO is present. This makes it possible to drop the legacy include header from the RB532 devices. Signed-off-by: Linus Walleij Acked-by: Miquel Raynal Signed-off-by: Thomas Bogendoerfer --- arch/mips/rb532/devices.c | 36 +++++++++++++++++++------------- drivers/mtd/nand/raw/plat_nand.c | 24 ++++++++++++++++++++- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/arch/mips/rb532/devices.c b/arch/mips/rb532/devices.c index 3f56d9feb73a..c3d8d96d0ef5 100644 --- a/arch/mips/rb532/devices.c +++ b/arch/mips/rb532/devices.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -135,12 +134,6 @@ static struct platform_device cf_slot0 = { .num_resources = ARRAY_SIZE(cf_slot0_res), }; -/* Resources and device for NAND */ -static int rb532_dev_ready(struct nand_chip *chip) -{ - return gpio_get_value(GPIO_RDY); -} - static void rb532_cmd_ctrl(struct nand_chip *chip, int cmd, unsigned int ctrl) { unsigned char orbits, nandbits; @@ -166,16 +159,23 @@ static struct resource nand_slot0_res[] = { }; static struct platform_nand_data rb532_nand_data = { - .ctrl.dev_ready = rb532_dev_ready, .ctrl.cmd_ctrl = rb532_cmd_ctrl, }; -static struct platform_device nand_slot0 = { - .name = "gen_nand", - .id = -1, - .resource = nand_slot0_res, - .num_resources = ARRAY_SIZE(nand_slot0_res), - .dev.platform_data = &rb532_nand_data, +static const struct property_entry nand0_properties[] = { + PROPERTY_ENTRY_GPIO("ready-gpios", &rb532_gpio0_node, + GPIO_RDY, GPIO_ACTIVE_HIGH), + { } +}; + +static const struct platform_device_info nand0_info __initconst = { + .name = "gen_nand", + .id = PLATFORM_DEVID_NONE, + .res = nand_slot0_res, + .num_res = ARRAY_SIZE(nand_slot0_res), + .data = &rb532_nand_data, + .size_data = sizeof(struct platform_nand_data), + .properties = nand0_properties, }; static struct mtd_partition rb532_partition_info[] = { @@ -234,7 +234,6 @@ static struct platform_device rb532_uart = { static struct platform_device *rb532_devs[] = { &korina_dev0, - &nand_slot0, &cf_slot0, &rb532_led, &rb532_uart, @@ -321,6 +320,13 @@ static int __init plat_setup_devices(void) */ software_node_register(&rb532_gpio0_node); + pd = platform_device_register_full(&nand0_info); + ret = PTR_ERR_OR_ZERO(pd); + if (ret) { + pr_err("failed to create NAND slot0 device: %d\n", ret); + return ret; + } + pd = platform_device_register_full(&rb532_button_info); ret = PTR_ERR_OR_ZERO(pd); if (ret) { diff --git a/drivers/mtd/nand/raw/plat_nand.c b/drivers/mtd/nand/raw/plat_nand.c index 0bcd455328ef..fe31551bcf5f 100644 --- a/drivers/mtd/nand/raw/plat_nand.c +++ b/drivers/mtd/nand/raw/plat_nand.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -17,6 +18,7 @@ struct plat_nand_data { struct nand_controller controller; struct nand_chip chip; void __iomem *io_base; + struct gpio_desc *ready_gpio; }; static int plat_nand_attach_chip(struct nand_chip *chip) @@ -32,6 +34,14 @@ static const struct nand_controller_ops plat_nand_ops = { .attach_chip = plat_nand_attach_chip, }; +/* Resources and device for NAND */ +static int plat_nand_gpio_dev_ready(struct nand_chip *chip) +{ + struct plat_nand_data *data = nand_get_controller_data(chip); + + return gpiod_get_value(data->ready_gpio); +} + /* * Probe for the NAND device. */ @@ -41,6 +51,7 @@ static int plat_nand_probe(struct platform_device *pdev) struct plat_nand_data *data; struct mtd_info *mtd; const char **part_types; + struct nand_chip *chip; int err = 0; if (!pdata) { @@ -59,9 +70,17 @@ static int plat_nand_probe(struct platform_device *pdev) if (!data) return -ENOMEM; + data->ready_gpio = devm_gpiod_get_optional(&pdev->dev, "ready", + GPIOD_IN); + if (IS_ERR(data->ready_gpio)) + return dev_err_probe(&pdev->dev, PTR_ERR(data->ready_gpio), + "could not get READY GPIO\n"); + data->controller.ops = &plat_nand_ops; nand_controller_init(&data->controller); data->chip.controller = &data->controller; + chip = &data->chip; + nand_set_controller_data(chip, data); data->io_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(data->io_base)) @@ -74,7 +93,10 @@ static int plat_nand_probe(struct platform_device *pdev) data->chip.legacy.IO_ADDR_R = data->io_base; data->chip.legacy.IO_ADDR_W = data->io_base; data->chip.legacy.cmd_ctrl = pdata->ctrl.cmd_ctrl; - data->chip.legacy.dev_ready = pdata->ctrl.dev_ready; + if (data->ready_gpio) + data->chip.legacy.dev_ready = plat_nand_gpio_dev_ready; + else + data->chip.legacy.dev_ready = pdata->ctrl.dev_ready; data->chip.legacy.select_chip = pdata->ctrl.select_chip; data->chip.legacy.write_buf = pdata->ctrl.write_buf; data->chip.legacy.read_buf = pdata->ctrl.read_buf;