summaryrefslogtreecommitdiffstats
path: root/drivers/soc/renesas
diff options
context:
space:
mode:
authorSteven Rostedt <rostedt@goodmis.org>2026-09-02 09:55:01 -0400
committerSteven Rostedt <rostedt@goodmis.org>2026-09-02 11:08:21 -0400
commit4617721c502b2ddaa4e324e86da4997edf738fa5 (patch)
tree350aa83b47da0b574a814795392b20b0bed83cbc /drivers/soc/renesas
downloadlinux-stable-4617721c502b2ddaa4e324e86da4997edf738fa5.tar.gz
linux-stable-4617721c502b2ddaa4e324e86da4997edf738fa5.zip
ftrace: Synchronize the initialization of ftrace_opsgrafted
There's some internal state that ftrace_ops needs to have set, but since it can be declared outside of the ftrace.c code, it calls ftrace_ops_init() on the ops in every global function. The issue is that if two tasks call it on the same ops at the same time it is possible to have the initialization of one corrupt the initialization of the other call. Create a ops_mutex to use to synchronize every initialization of the ftrace_ops. The mutex is taken within checking the ftrace_ops flag that states it was initializied but the flag is checked again after the mutex has been taken. Checking first outside the mutex allows it to shortcut having to take the mutex. But then the check needs to be done again after the mute is taken in case of races. Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260902095501.6b59af20@gandalf.local.home Fixes: f04f24fb7e48d ("ftrace, kprobes: Fix a deadlock on ftrace_regex_lock") Reported-by: sashiko-bot@kernel.org Close: https://lore.kernel.org/all/20260829025528.49A831F000E9@smtp.kernel.org/ Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'drivers/soc/renesas')
-rw-r--r--drivers/soc/renesas/Kconfig510
-rw-r--r--drivers/soc/renesas/Makefile20
-rw-r--r--drivers/soc/renesas/pwc-rzv2m.c143
-rw-r--r--drivers/soc/renesas/r9a06g032-smp.c96
-rw-r--r--drivers/soc/renesas/r9a08g045-sysc.c88
-rw-r--r--drivers/soc/renesas/r9a08g046-sysc.c86
-rw-r--r--drivers/soc/renesas/r9a09g047-sys.c137
-rw-r--r--drivers/soc/renesas/r9a09g056-sys.c139
-rw-r--r--drivers/soc/renesas/r9a09g057-sys.c153
-rw-r--r--drivers/soc/renesas/rcar-mfis.c384
-rw-r--r--drivers/soc/renesas/rcar-rst.c186
-rw-r--r--drivers/soc/renesas/renesas-soc.c560
-rw-r--r--drivers/soc/renesas/rz-sysc.c172
-rw-r--r--drivers/soc/renesas/rz-sysc.h54
-rw-r--r--drivers/soc/renesas/rzn1_irqmux.c126
15 files changed, 2854 insertions, 0 deletions
diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig
new file mode 100644
index 000000000..eb8ac0d47
--- /dev/null
+++ b/drivers/soc/renesas/Kconfig
@@ -0,0 +1,510 @@
+# SPDX-License-Identifier: GPL-2.0
+menuconfig SOC_RENESAS
+ bool "Renesas SoC driver support" if COMPILE_TEST && !ARCH_RENESAS
+ default y if ARCH_RENESAS
+ select GPIOLIB
+ select PINCTRL
+ select SOC_BUS
+
+if SOC_RENESAS
+
+config ARCH_RCAR_GEN1
+ bool
+ select PM
+ select PM_GENERIC_DOMAINS
+ select RENESAS_INTC_IRQPIN
+ select RST_RCAR
+ select SYS_SUPPORTS_SH_TMU
+
+config ARCH_RCAR_GEN2
+ bool
+ select HAVE_ARM_ARCH_TIMER
+ select PM
+ select PM_GENERIC_DOMAINS
+ select RENESAS_IRQC
+ select RST_RCAR
+ select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_TMU
+
+config ARCH_RCAR_GEN3
+ bool
+ select PM
+ select PM_GENERIC_DOMAINS
+ select RENESAS_IRQC
+ select RST_RCAR
+ select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_TMU
+
+config ARCH_RCAR_GEN4
+ bool
+ select ARCH_RCAR_GEN3
+
+config ARCH_RCAR_GEN5
+ bool
+ select ARCH_RCAR_GEN4
+
+config ARCH_RMOBILE
+ bool
+ select PM
+ select PM_GENERIC_DOMAINS
+ select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_TMU
+ select SYSC_RMOBILE
+
+config ARCH_RZG2L
+ bool
+ select PM
+ select PM_GENERIC_DOMAINS
+ select RENESAS_RZG2L_IRQC
+
+config ARCH_RZN1
+ bool
+ select PM
+ select PM_GENERIC_DOMAINS
+ select ARM_AMBA
+ select RZN1_IRQMUX if GPIO_DWAPB
+
+if ARM && ARCH_RENESAS
+
+#comment "Renesas ARM SoCs System Type"
+
+config ARCH_EMEV2
+ bool "ARM32 Platform support for Emma Mobile EV2"
+ default ARCH_RENESAS
+ select HAVE_ARM_SCU if SMP
+ select SYS_SUPPORTS_EM_STI
+
+config ARCH_R7S72100
+ bool "ARM32 Platform support for R7S72100 (RZ/A1H)"
+ default ARCH_RENESAS
+ select ARM_ERRATA_754322
+ select PM
+ select PM_GENERIC_DOMAINS
+ select RENESAS_OSTM
+ select RENESAS_RZA1_IRQC
+ select SYS_SUPPORTS_SH_MTU2
+
+config ARCH_R7S9210
+ bool "ARM32 Platform support for R7S9210 (RZ/A2)"
+ default ARCH_RENESAS
+ select PM
+ select PM_GENERIC_DOMAINS
+ select RENESAS_OSTM
+ select RENESAS_RZA1_IRQC
+
+config ARCH_R8A73A4
+ bool "ARM32 Platform support for R8A73A4 (R-Mobile APE6)"
+ default ARCH_RENESAS
+ select ARCH_RMOBILE
+ select ARM_ERRATA_798181 if SMP
+ select ARM_ERRATA_814220
+ select HAVE_ARM_ARCH_TIMER
+ select RENESAS_IRQC
+
+config ARCH_R8A7740
+ bool "ARM32 Platform support for R8A7740 (R-Mobile A1)"
+ default ARCH_RENESAS
+ select ARCH_RMOBILE
+ select ARM_ERRATA_754322
+ select RENESAS_INTC_IRQPIN
+
+config ARCH_R8A7742
+ bool "ARM32 Platform support for R8A7742 (RZ/G1H)"
+ default ARCH_RENESAS
+ select ARCH_RCAR_GEN2
+ select ARM_ERRATA_798181 if SMP
+ select ARM_ERRATA_814220
+ select SYSC_R8A7742
+
+config ARCH_R8A7743
+ bool "ARM32 Platform support for R8A7743 (RZ/G1M)"
+ default ARCH_RENESAS
+ select ARCH_RCAR_GEN2
+ select ARM_ERRATA_798181 if SMP
+ select SYSC_R8A7743
+
+config ARCH_R8A7744
+ bool "ARM32 Platform support for R8A7744 (RZ/G1N)"
+ default ARCH_RENESAS
+ select ARCH_RCAR_GEN2
+ select ARM_ERRATA_798181 if SMP
+ select SYSC_R8A7743
+
+config ARCH_R8A7745
+ bool "ARM32 Platform support for R8A7745 (RZ/G1E)"
+ default ARCH_RENESAS
+ select ARCH_RCAR_GEN2
+ select ARM_ERRATA_814220
+ select SYSC_R8A7745
+
+config ARCH_R8A77470
+ bool "ARM32 Platform support for R8A77470 (RZ/G1C)"
+ default ARCH_RENESAS
+ select ARCH_RCAR_GEN2
+ select ARM_ERRATA_814220
+ select SYSC_R8A77470
+
+config ARCH_R8A7778
+ bool "ARM32 Platform support for R8A7778 (R-Car M1A)"
+ default ARCH_RENESAS
+ select ARCH_RCAR_GEN1
+ select ARM_ERRATA_754322
+
+config ARCH_R8A7779
+ bool "ARM32 Platform support for R8A7779 (R-Car H1)"
+ default ARCH_RENESAS
+ select ARCH_RCAR_GEN1
+ select ARM_ERRATA_754322
+ select ARM_GLOBAL_TIMER
+ select HAVE_ARM_SCU if SMP
+ select HAVE_ARM_TWD if SMP
+ select SYSC_R8A7779
+
+config ARCH_R8A7790
+ bool "ARM32 Platform support for R8A7790 (R-Car H2)"
+ default ARCH_RENESAS
+ select ARCH_RCAR_GEN2
+ select ARM_ERRATA_798181 if SMP
+ select ARM_ERRATA_814220
+ select I2C
+ select SYSC_R8A7790
+
+config ARCH_R8A7791
+ bool "ARM32 Platform support for R8A7791 (R-Car M2-W)"
+ default ARCH_RENESAS
+ select ARCH_RCAR_GEN2
+ select ARM_ERRATA_798181 if SMP
+ select I2C
+ select SYSC_R8A7791
+
+config ARCH_R8A7792
+ bool "ARM32 Platform support for R8A7792 (R-Car V2H)"
+ default ARCH_RENESAS
+ select ARCH_RCAR_GEN2
+ select ARM_ERRATA_798181 if SMP
+ select SYSC_R8A7792
+
+config ARCH_R8A7793
+ bool "ARM32 Platform support for R8A7793 (R-Car M2-N)"
+ default ARCH_RENESAS
+ select ARCH_RCAR_GEN2
+ select ARM_ERRATA_798181 if SMP
+ select I2C
+ select SYSC_R8A7791
+
+config ARCH_R8A7794
+ bool "ARM32 Platform support for R8A7794 (R-Car E2)"
+ default ARCH_RENESAS
+ select ARCH_RCAR_GEN2
+ select ARM_ERRATA_814220
+ select SYSC_R8A7794
+
+config ARCH_R9A06G032
+ bool "ARM32 Platform support for R9A06G032 (RZ/N1D)"
+ default ARCH_RENESAS
+ select ARCH_RZN1
+ select ARM_ERRATA_814220
+
+config ARCH_SH73A0
+ bool "ARM32 Platform support for SH73A0 (SH-Mobile AG5)"
+ default ARCH_RENESAS
+ select ARCH_RMOBILE
+ select ARM_ERRATA_754322
+ select ARM_GLOBAL_TIMER
+ select HAVE_ARM_SCU if SMP
+ select HAVE_ARM_TWD if SMP
+ select RENESAS_INTC_IRQPIN
+
+endif # ARM
+
+if ARM64
+
+config ARCH_R8A774A1
+ bool "ARM64 Platform support for R8A774A1 (RZ/G2M)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN3
+ select SYSC_R8A774A1
+ help
+ This enables support for the Renesas RZ/G2M SoC.
+
+config ARCH_R8A774B1
+ bool "ARM64 Platform support for R8A774B1 (RZ/G2N)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN3
+ select SYSC_R8A774B1
+ help
+ This enables support for the Renesas RZ/G2N SoC.
+
+config ARCH_R8A774C0
+ bool "ARM64 Platform support for R8A774C0 (RZ/G2E)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN3
+ select SYSC_R8A774C0
+ help
+ This enables support for the Renesas RZ/G2E SoC.
+
+config ARCH_R8A774E1
+ bool "ARM64 Platform support for R8A774E1 (RZ/G2H)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN3
+ select SYSC_R8A774E1
+ help
+ This enables support for the Renesas RZ/G2H SoC.
+
+config ARCH_R8A77951
+ bool "ARM64 Platform support for R8A77951 (R-Car H3 ES2.0+)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN3
+ select SYSC_R8A7795
+ help
+ This enables support for the Renesas R-Car H3 SoC (revisions 2.0 and
+ later).
+ This includes different gradings like R-Car H3e, H3e-2G, and H3Ne.
+
+config ARCH_R8A77960
+ bool "ARM64 Platform support for R8A77960 (R-Car M3-W)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN3
+ select SYSC_R8A77960
+ help
+ This enables support for the Renesas R-Car M3-W SoC.
+
+config ARCH_R8A77961
+ bool "ARM64 Platform support for R8A77961 (R-Car M3-W+)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN3
+ select SYSC_R8A77961
+ help
+ This enables support for the Renesas R-Car M3-W+ SoC.
+ This includes different gradings like R-Car M3e and M3e-2G.
+
+config ARCH_R8A77965
+ bool "ARM64 Platform support for R8A77965 (R-Car M3-N)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN3
+ select SYSC_R8A77965
+ help
+ This enables support for the Renesas R-Car M3-N SoC.
+ This includes different gradings like R-Car M3Ne and M3Ne-2G.
+
+config ARCH_R8A77970
+ bool "ARM64 Platform support for R8A77970 (R-Car V3M)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN3
+ select SYSC_R8A77970
+ help
+ This enables support for the Renesas R-Car V3M SoC.
+
+config ARCH_R8A77980
+ bool "ARM64 Platform support for R8A77980 (R-Car V3H)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN3
+ select SYSC_R8A77980
+ help
+ This enables support for the Renesas R-Car V3H SoC.
+
+config ARCH_R8A77990
+ bool "ARM64 Platform support for R8A77990 (R-Car E3)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN3
+ select SYSC_R8A77990
+ help
+ This enables support for the Renesas R-Car E3 SoC.
+ This includes different gradings like R-Car E3e.
+
+config ARCH_R8A77995
+ bool "ARM64 Platform support for R8A77995 (R-Car D3)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN3
+ select SYSC_R8A77995
+ help
+ This enables support for the Renesas R-Car D3 SoC.
+ This includes different gradings like R-Car D3e.
+
+config ARCH_R8A779A0
+ bool "ARM64 Platform support for R8A779A0 (R-Car V3U)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN4
+ select SYSC_R8A779A0
+ help
+ This enables support for the Renesas R-Car V3U SoC.
+
+config ARCH_R8A779F0
+ bool "ARM64 Platform support for R8A779F0 (R-Car S4-8)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN4
+ select SYSC_R8A779F0
+ help
+ This enables support for the Renesas R-Car S4-8 SoC.
+
+config ARCH_R8A779G0
+ bool "ARM64 Platform support for R8A779G0 (R-Car V4H)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN4
+ select SYSC_R8A779G0
+ help
+ This enables support for the Renesas R-Car V4H SoC.
+
+config ARCH_R8A779H0
+ bool "ARM64 Platform support for R8A779H0 (R-Car V4M)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN4
+ select SYSC_R8A779H0
+ help
+ This enables support for the Renesas R-Car V4M SoC.
+
+config ARCH_R8A78000
+ bool "ARM64 Platform support for R8A78000 (R-Car X5H)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN5
+ select MDLC_R8A78000
+ help
+ This enables support for the Renesas R-Car X5H SoC.
+
+config ARCH_R9A07G043
+ bool "ARM64 Platform support for R9A07G043U (RZ/G2UL)"
+ default y if ARCH_RENESAS
+ select ARCH_RZG2L
+ help
+ This enables support for the Renesas RZ/G2UL SoC variants.
+
+config ARCH_R9A07G044
+ bool "ARM64 Platform support for R9A07G044 (RZ/G2L)"
+ default y if ARCH_RENESAS
+ select ARCH_RZG2L
+ help
+ This enables support for the Renesas RZ/G2L SoC variants.
+
+config ARCH_R9A07G054
+ bool "ARM64 Platform support for R9A07G054 (RZ/V2L)"
+ default y if ARCH_RENESAS
+ select ARCH_RZG2L
+ help
+ This enables support for the Renesas RZ/V2L SoC variants.
+
+config ARCH_R9A08G045
+ bool "ARM64 Platform support for R9A08G045 (RZ/G3S)"
+ default y if ARCH_RENESAS
+ select ARCH_RZG2L
+ select SYSC_R9A08G045
+ help
+ This enables support for the Renesas RZ/G3S SoC variants.
+
+config ARCH_R9A08G046
+ bool "ARM64 Platform support for R9A08G046 (RZ/G3L)"
+ default y if ARCH_RENESAS
+ select ARCH_RZG2L
+ select SYSC_R9A08G046
+ help
+ This enables support for the Renesas RZ/G3L SoC variants.
+
+config ARCH_R9A09G011
+ bool "ARM64 Platform support for R9A09G011 (RZ/V2M)"
+ default y if ARCH_RENESAS
+ select PM
+ select PM_GENERIC_DOMAINS
+ select PWC_RZV2M
+ help
+ This enables support for the Renesas RZ/V2M SoC.
+
+config ARCH_R9A09G047
+ bool "ARM64 Platform support for R9A09G047 (RZ/G3E)"
+ default y if ARCH_RENESAS
+ select SYS_R9A09G047
+ help
+ This enables support for the Renesas RZ/G3E SoC variants.
+
+config ARCH_R9A09G056
+ bool "ARM64 Platform support for R9A09G056 (RZ/V2N)"
+ default y if ARCH_RENESAS
+ select SYS_R9A09G056
+ help
+ This enables support for the Renesas RZ/V2N SoC variants.
+
+config ARCH_R9A09G057
+ bool "ARM64 Platform support for R9A09G057 (RZ/V2H(P))"
+ default y if ARCH_RENESAS
+ select RENESAS_RZV2H_ICU
+ select SYS_R9A09G057
+ help
+ This enables support for the Renesas RZ/V2H(P) SoC variants.
+
+config ARCH_R9A09G077
+ bool "ARM64 Platform support for R9A09G077 (RZ/T2H)"
+ default y if ARCH_RENESAS
+ select RENESAS_RZT2H_ICU
+ help
+ This enables support for the Renesas RZ/T2H SoC variants.
+
+config ARCH_R9A09G087
+ bool "ARM64 Platform support for R9A09G087 (RZ/N2H)"
+ default y if ARCH_RENESAS
+ select RENESAS_RZT2H_ICU
+ help
+ This enables support for the Renesas RZ/N2H SoC variants.
+
+endif # ARM64
+
+if RISCV
+
+config ARCH_R9A07G043
+ bool "RISC-V Platform support for R9A07G043F (RZ/Five)"
+ depends on NONPORTABLE
+ depends on !DMA_DIRECT_REMAP
+ depends on RISCV_ALTERNATIVE
+ depends on !RISCV_ISA_ZICBOM
+ depends on RISCV_SBI
+ select ARCH_RZG2L
+ select AX45MP_L2_CACHE
+ select CACHEMAINT_FOR_DMA
+ select DMA_GLOBAL_POOL
+ select ERRATA_ANDES
+ select ERRATA_ANDES_CMO
+ help
+ This enables support for the Renesas RZ/Five SoC.
+
+endif # RISCV
+
+config RCAR_MFIS
+ tristate "Renesas R-Car MFIS driver"
+ depends on ARCH_RENESAS || COMPILE_TEST
+ depends on MAILBOX
+ help
+ Select this option to enable the Renesas R-Car MFIS core driver for
+ the MFIS device found on SoCs like R-Car. On families like Gen5, this
+ is needed to communicate with the SCP.
+
+config PWC_RZV2M
+ bool "Renesas RZ/V2M PWC support" if COMPILE_TEST
+
+config RST_RCAR
+ bool "Reset Controller support for R-Car" if COMPILE_TEST
+
+config RZN1_IRQMUX
+ bool "Renesas RZ/N1 GPIO IRQ multiplexer support" if COMPILE_TEST
+
+config SYSC_RZ
+ bool "System controller for RZ SoCs" if COMPILE_TEST
+ select MFD_SYSCON
+
+config SYSC_R9A08G045
+ bool "Renesas System controller support for R9A08G045 (RZ/G3S)" if COMPILE_TEST
+ select SYSC_RZ
+
+config SYSC_R9A08G046
+ bool "Renesas System controller support for R9A08G046 (RZ/G3L)" if COMPILE_TEST
+ select SYSC_RZ
+
+config SYS_R9A09G047
+ bool "Renesas System controller support for R9A09G047 (RZ/G3E)" if COMPILE_TEST
+ select SYSC_RZ
+
+config SYS_R9A09G056
+ bool "Renesas System controller support for R9A09G056 (RZ/V2N)" if COMPILE_TEST
+ select SYSC_RZ
+
+config SYS_R9A09G057
+ bool "Renesas System controller support for R9A09G057 (RZ/V2H)" if COMPILE_TEST
+ select SYSC_RZ
+
+endif # SOC_RENESAS
diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile
new file mode 100644
index 000000000..81bde85c2
--- /dev/null
+++ b/drivers/soc/renesas/Makefile
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-2.0
+# Generic, must be first because of soc_device_register()
+obj-$(CONFIG_SOC_RENESAS) += renesas-soc.o
+
+# SoC
+ifdef CONFIG_SMP
+obj-$(CONFIG_ARCH_R9A06G032) += r9a06g032-smp.o
+endif
+obj-$(CONFIG_SYSC_R9A08G045) += r9a08g045-sysc.o
+obj-$(CONFIG_SYSC_R9A08G046) += r9a08g046-sysc.o
+obj-$(CONFIG_SYS_R9A09G047) += r9a09g047-sys.o
+obj-$(CONFIG_SYS_R9A09G056) += r9a09g056-sys.o
+obj-$(CONFIG_SYS_R9A09G057) += r9a09g057-sys.o
+
+# Family
+obj-$(CONFIG_PWC_RZV2M) += pwc-rzv2m.o
+obj-$(CONFIG_RCAR_MFIS) += rcar-mfis.o
+obj-$(CONFIG_RST_RCAR) += rcar-rst.o
+obj-$(CONFIG_RZN1_IRQMUX) += rzn1_irqmux.o
+obj-$(CONFIG_SYSC_RZ) += rz-sysc.o
diff --git a/drivers/soc/renesas/pwc-rzv2m.c b/drivers/soc/renesas/pwc-rzv2m.c
new file mode 100644
index 000000000..6209168b3
--- /dev/null
+++ b/drivers/soc/renesas/pwc-rzv2m.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 Renesas Electronics Corporation
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/driver.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+
+#define PWC_PWCRST 0x00
+#define PWC_PWCCKEN 0x04
+#define PWC_PWCCTL 0x50
+#define PWC_GPIO 0x80
+
+#define PWC_PWCRST_RSTSOFTAX 0x1
+#define PWC_PWCCKEN_ENGCKMAIN 0x1
+#define PWC_PWCCTL_PWOFF 0x1
+
+struct rzv2m_pwc_priv {
+ void __iomem *base;
+ struct device *dev;
+ struct gpio_chip gp;
+ DECLARE_BITMAP(ch_en_bits, 2);
+};
+
+static int rzv2m_pwc_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ struct rzv2m_pwc_priv *priv = gpiochip_get_data(chip);
+ u32 reg;
+
+ /* BIT 16 enables write to BIT 0, and BIT 17 enables write to BIT 1 */
+ reg = BIT(offset + 16);
+ if (value)
+ reg |= BIT(offset);
+
+ writel(reg, priv->base + PWC_GPIO);
+
+ assign_bit(offset, priv->ch_en_bits, value);
+
+ return 0;
+}
+
+static int rzv2m_pwc_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct rzv2m_pwc_priv *priv = gpiochip_get_data(chip);
+
+ return test_bit(offset, priv->ch_en_bits);
+}
+
+static int rzv2m_pwc_gpio_direction_output(struct gpio_chip *gc,
+ unsigned int nr, int value)
+{
+ if (nr > 1)
+ return -EINVAL;
+
+ rzv2m_pwc_gpio_set(gc, nr, value);
+
+ return 0;
+}
+
+static const struct gpio_chip rzv2m_pwc_gc = {
+ .label = "gpio_rzv2m_pwc",
+ .owner = THIS_MODULE,
+ .get = rzv2m_pwc_gpio_get,
+ .set = rzv2m_pwc_gpio_set,
+ .direction_output = rzv2m_pwc_gpio_direction_output,
+ .can_sleep = false,
+ .ngpio = 2,
+ .base = -1,
+};
+
+static int rzv2m_pwc_poweroff(struct sys_off_data *data)
+{
+ struct rzv2m_pwc_priv *priv = data->cb_data;
+
+ writel(PWC_PWCRST_RSTSOFTAX, priv->base + PWC_PWCRST);
+ writel(PWC_PWCCKEN_ENGCKMAIN, priv->base + PWC_PWCCKEN);
+ writel(PWC_PWCCTL_PWOFF, priv->base + PWC_PWCCTL);
+
+ mdelay(150);
+
+ dev_err(priv->dev, "Failed to power off the system");
+
+ return NOTIFY_DONE;
+}
+
+static int rzv2m_pwc_probe(struct platform_device *pdev)
+{
+ struct rzv2m_pwc_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ /*
+ * The register used by this driver cannot be read, therefore set the
+ * outputs to their default values and initialize priv->ch_en_bits
+ * accordingly. BIT 16 enables write to BIT 0, BIT 17 enables write to
+ * BIT 1, and the default value of both BIT 0 and BIT 1 is 0.
+ */
+ writel(BIT(17) | BIT(16), priv->base + PWC_GPIO);
+ bitmap_zero(priv->ch_en_bits, 2);
+
+ priv->gp = rzv2m_pwc_gc;
+ priv->gp.parent = pdev->dev.parent;
+ priv->gp.fwnode = dev_fwnode(&pdev->dev);
+
+ ret = devm_gpiochip_add_data(&pdev->dev, &priv->gp, priv);
+ if (ret)
+ return ret;
+
+ if (device_property_read_bool(&pdev->dev, "renesas,rzv2m-pwc-power"))
+ ret = devm_register_power_off_handler(&pdev->dev,
+ rzv2m_pwc_poweroff, priv);
+
+ return ret;
+}
+
+static const struct of_device_id rzv2m_pwc_of_match[] = {
+ { .compatible = "renesas,rzv2m-pwc" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rzv2m_pwc_of_match);
+
+static struct platform_driver rzv2m_pwc_driver = {
+ .probe = rzv2m_pwc_probe,
+ .driver = {
+ .name = "rzv2m_pwc",
+ .of_match_table = rzv2m_pwc_of_match,
+ },
+};
+module_platform_driver(rzv2m_pwc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Fabrizio Castro <castro.fabrizio.jz@renesas.com>");
+MODULE_DESCRIPTION("Renesas RZ/V2M PWC driver");
diff --git a/drivers/soc/renesas/r9a06g032-smp.c b/drivers/soc/renesas/r9a06g032-smp.c
new file mode 100644
index 000000000..a1926e8d7
--- /dev/null
+++ b/drivers/soc/renesas/r9a06g032-smp.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * R9A06G032 Second CA7 enabler.
+ *
+ * Copyright (C) 2018 Renesas Electronics Europe Limited
+ *
+ * Michel Pollet <michel.pollet@bp.renesas.com>, <buserror@gmail.com>
+ * Derived from actions,s500-smp
+ */
+
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/smp.h>
+
+/*
+ * The second CPU is parked in ROM at boot time. It requires waking it after
+ * writing an address into the BOOTADDR register of sysctrl.
+ *
+ * So the default value of the "cpu-release-addr" corresponds to BOOTADDR...
+ *
+ * *However* the BOOTADDR register is not available when the kernel
+ * starts in NONSEC mode.
+ *
+ * So for NONSEC mode, the bootloader re-parks the second CPU into a pen
+ * in SRAM, and changes the "cpu-release-addr" of linux's DT to a SRAM address,
+ * which is not restricted.
+ */
+
+static void __iomem *cpu_bootaddr;
+
+static DEFINE_SPINLOCK(cpu_lock);
+
+static int
+r9a06g032_smp_boot_secondary(unsigned int cpu,
+ struct task_struct *idle)
+{
+ if (!cpu_bootaddr)
+ return -ENODEV;
+
+ spin_lock(&cpu_lock);
+
+ writel(__pa_symbol(secondary_startup), cpu_bootaddr);
+ arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+
+ spin_unlock(&cpu_lock);
+
+ return 0;
+}
+
+static void __init r9a06g032_smp_prepare_cpus(unsigned int max_cpus)
+{
+ struct device_node *dn;
+ int ret = -EINVAL, dns;
+ u32 bootaddr;
+
+ dn = of_get_cpu_node(1, NULL);
+ if (!dn) {
+ pr_err("CPU#1: missing device tree node\n");
+ return;
+ }
+ /*
+ * Determine the address from which the CPU is polling.
+ * The bootloader *does* change this property.
+ * Note: The property can be either 64 or 32 bits, so handle both cases
+ */
+ if (of_find_property(dn, "cpu-release-addr", &dns)) {
+ if (dns == sizeof(u64)) {
+ u64 temp;
+
+ ret = of_property_read_u64(dn,
+ "cpu-release-addr", &temp);
+ bootaddr = temp;
+ } else {
+ ret = of_property_read_u32(dn,
+ "cpu-release-addr",
+ &bootaddr);
+ }
+ }
+ of_node_put(dn);
+ if (ret) {
+ pr_err("CPU#1: invalid cpu-release-addr property\n");
+ return;
+ }
+ pr_info("CPU#1: cpu-release-addr %08x\n", bootaddr);
+
+ cpu_bootaddr = ioremap(bootaddr, sizeof(bootaddr));
+}
+
+static const struct smp_operations r9a06g032_smp_ops __initconst = {
+ .smp_prepare_cpus = r9a06g032_smp_prepare_cpus,
+ .smp_boot_secondary = r9a06g032_smp_boot_secondary,
+};
+
+CPU_METHOD_OF_DECLARE(r9a06g032_smp,
+ "renesas,r9a06g032-smp", &r9a06g032_smp_ops);
diff --git a/drivers/soc/renesas/r9a08g045-sysc.c b/drivers/soc/renesas/r9a08g045-sysc.c
new file mode 100644
index 000000000..63e4aa6a7
--- /dev/null
+++ b/drivers/soc/renesas/r9a08g045-sysc.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/G3S System controller driver
+ *
+ * Copyright (C) 2024 Renesas Electronics Corp.
+ */
+
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/init.h>
+
+#include "rz-sysc.h"
+
+#define SYS_XSPI_MAP_STAADD_CS0 0x348
+#define SYS_XSPI_MAP_ENDADD_CS0 0x34c
+#define SYS_XSPI_MAP_STAADD_CS1 0x350
+#define SYS_XSPI_MAP_ENDADD_CS1 0x354
+#define SYS_GETH0_CFG 0x380
+#define SYS_GETH1_CFG 0x390
+#define SYS_PCIE_CFG 0x3a0
+#define SYS_PCIE_MON 0x3a4
+#define SYS_PCIE_ERR_MON 0x3ac
+#define SYS_PCIE_PHY 0x3b4
+#define SYS_I2C0_CFG 0x400
+#define SYS_I2C1_CFG 0x410
+#define SYS_I2C2_CFG 0x420
+#define SYS_I2C3_CFG 0x430
+#define SYS_I3C_CFG 0x440
+#define SYS_USB_PWRRDY 0xd70
+#define SYS_PCIE_RST_RSM_B 0xd74
+
+static const struct rz_sysc_soc_id_init_data rzg3s_sysc_soc_id_init_data __initconst = {
+ .family = "RZ/G3S",
+ .id = 0x85e0447,
+ .devid_offset = 0xa04,
+ .revision_mask = GENMASK(31, 28),
+ .specific_id_mask = GENMASK(27, 0),
+};
+
+static bool rzg3s_regmap_readable_writeable_reg(unsigned int reg)
+{
+ switch (reg) {
+ case SYS_XSPI_MAP_STAADD_CS0:
+ case SYS_XSPI_MAP_ENDADD_CS0:
+ case SYS_XSPI_MAP_STAADD_CS1:
+ case SYS_XSPI_MAP_ENDADD_CS1:
+ case SYS_PCIE_CFG:
+ case SYS_PCIE_PHY:
+ case SYS_I2C0_CFG:
+ case SYS_I2C1_CFG:
+ case SYS_I2C2_CFG:
+ case SYS_I2C3_CFG:
+ case SYS_I3C_CFG:
+ case SYS_USB_PWRRDY:
+ case SYS_PCIE_RST_RSM_B:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rzg3s_regmap_readable_reg(struct device *dev, unsigned int reg)
+{
+ if (rzg3s_regmap_readable_writeable_reg(reg))
+ return true;
+
+ switch (reg) {
+ case SYS_GETH0_CFG:
+ case SYS_GETH1_CFG:
+ case SYS_PCIE_MON:
+ case SYS_PCIE_ERR_MON:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rzg3s_regmap_writeable_reg(struct device *dev, unsigned int reg)
+{
+ return rzg3s_regmap_readable_writeable_reg(reg);
+}
+
+const struct rz_sysc_init_data rzg3s_sysc_init_data __initconst = {
+ .soc_id_init_data = &rzg3s_sysc_soc_id_init_data,
+ .readable_reg = rzg3s_regmap_readable_reg,
+ .writeable_reg = rzg3s_regmap_writeable_reg,
+ .max_register = 0xe20,
+};
diff --git a/drivers/soc/renesas/r9a08g046-sysc.c b/drivers/soc/renesas/r9a08g046-sysc.c
new file mode 100644
index 000000000..90db9d383
--- /dev/null
+++ b/drivers/soc/renesas/r9a08g046-sysc.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/G3L System controller (SYSC) driver
+ *
+ * Copyright (C) 2026 Renesas Electronics Corp.
+ */
+
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/init.h>
+
+#include "rz-sysc.h"
+
+#define SYS_XSPI_MAP_STAADD_CS0 0x348
+#define SYS_XSPI_MAP_ENDADD_CS0 0x34c
+#define SYS_XSPI_MAP_STAADD_CS1 0x350
+#define SYS_XSPI_MAP_ENDADD_CS1 0x354
+#define SYS_GETH0_CFG 0x380
+#define SYS_GETH1_CFG 0x390
+#define SYS_PCIE_CFG 0x3a0
+#define SYS_PCIE_MON 0x3a4
+#define SYS_PCIE_PHY 0x3b4
+#define SYS_I2C0_CFG 0x400
+#define SYS_I2C1_CFG 0x410
+#define SYS_I2C2_CFG 0x420
+#define SYS_I2C3_CFG 0x430
+#define SYS_I3C_CFG 0x440
+#define SYS_PWRRDY_N 0xd70
+#define SYS_IPCONT_SEL_CLONECH 0xe2c
+
+static bool rzg3l_regmap_readable_writeable_reg(unsigned int reg)
+{
+ switch (reg) {
+ case SYS_XSPI_MAP_STAADD_CS0:
+ case SYS_XSPI_MAP_ENDADD_CS0:
+ case SYS_XSPI_MAP_STAADD_CS1:
+ case SYS_XSPI_MAP_ENDADD_CS1:
+ case SYS_PCIE_CFG:
+ case SYS_PCIE_PHY:
+ case SYS_I2C0_CFG:
+ case SYS_I2C1_CFG:
+ case SYS_I2C2_CFG:
+ case SYS_I2C3_CFG:
+ case SYS_I3C_CFG:
+ case SYS_PWRRDY_N:
+ case SYS_IPCONT_SEL_CLONECH:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rzg3l_regmap_readable_reg(struct device *dev, unsigned int reg)
+{
+ if (rzg3l_regmap_readable_writeable_reg(reg))
+ return true;
+
+ switch (reg) {
+ case SYS_GETH0_CFG:
+ case SYS_GETH1_CFG:
+ case SYS_PCIE_MON:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rzg3l_regmap_writeable_reg(struct device *dev, unsigned int reg)
+{
+ return rzg3l_regmap_readable_writeable_reg(reg);
+}
+
+static const struct rz_sysc_soc_id_init_data rzg3l_sysc_soc_id_init_data __initconst = {
+ .family = "RZ/G3L",
+ .id = 0x87d9447,
+ .devid_offset = 0xa04,
+ .revision_mask = GENMASK(31, 28),
+ .specific_id_mask = GENMASK(27, 0),
+};
+
+const struct rz_sysc_init_data rzg3l_sysc_init_data __initconst = {
+ .soc_id_init_data = &rzg3l_sysc_soc_id_init_data,
+ .readable_reg = rzg3l_regmap_readable_reg,
+ .writeable_reg = rzg3l_regmap_writeable_reg,
+ .max_register = 0xe2c,
+};
diff --git a/drivers/soc/renesas/r9a09g047-sys.c b/drivers/soc/renesas/r9a09g047-sys.c
new file mode 100644
index 000000000..b617fb0bd
--- /dev/null
+++ b/drivers/soc/renesas/r9a09g047-sys.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/G3E System controller (SYS) driver
+ *
+ * Copyright (C) 2025 Renesas Electronics Corp.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include "rz-sysc.h"
+
+/* Register Offsets */
+#define SYS_LSI_MODE 0x300
+/*
+ * BOOTPLLCA[1:0]
+ * [0,0] => 1.1GHZ
+ * [0,1] => 1.5GHZ
+ * [1,0] => 1.6GHZ
+ * [1,1] => 1.7GHZ
+ */
+#define SYS_LSI_MODE_STAT_BOOTPLLCA55 GENMASK(12, 11)
+#define SYS_LSI_MODE_CA55_1_7GHZ 0x3
+
+#define SYS_LSI_PRR 0x308
+#define SYS_LSI_PRR_CA55_DIS BIT(8)
+#define SYS_LSI_PRR_NPU_DIS BIT(1)
+
+#define SYS_LSI_OTPTSU1TRMVAL0 0x330
+#define SYS_LSI_OTPTSU1TRMVAL1 0x334
+#define SYS_SPI_STAADDCS0 0x900
+#define SYS_SPI_ENDADDCS0 0x904
+#define SYS_SPI_STAADDCS1 0x908
+#define SYS_SPI_ENDADDCS1 0x90c
+#define SYS_VSP_CLK 0xe00
+#define SYS_GBETH0_CFG 0xf00
+#define SYS_GBETH1_CFG 0xf04
+#define SYS_PCIE_INTX_CH0 0x1000
+#define SYS_PCIE_MSI1_CH0 0x1004
+#define SYS_PCIE_MSI2_CH0 0x1008
+#define SYS_PCIE_MSI3_CH0 0x100c
+#define SYS_PCIE_MSI4_CH0 0x1010
+#define SYS_PCIE_MSI5_CH0 0x1014
+#define SYS_PCIE_PME_CH0 0x1018
+#define SYS_PCIE_ACK_CH0 0x101c
+#define SYS_PCIE_MISC_CH0 0x1020
+#define SYS_PCIE_MODE_CH0 0x1024
+#define SYS_ADC_CFG 0x1600
+
+static void rzg3e_sys_print_id(struct device *dev,
+ void __iomem *sysc_base,
+ struct soc_device_attribute *soc_dev_attr)
+{
+ bool is_quad_core, npu_enabled;
+ u32 prr_val, mode_val;
+
+ prr_val = readl(sysc_base + SYS_LSI_PRR);
+ mode_val = readl(sysc_base + SYS_LSI_MODE);
+
+ /* Check CPU and NPU configuration */
+ is_quad_core = !(prr_val & SYS_LSI_PRR_CA55_DIS);
+ npu_enabled = !(prr_val & SYS_LSI_PRR_NPU_DIS);
+
+ dev_info(dev, "Detected Renesas %s Core %s %s Rev %s%s\n",
+ is_quad_core ? "Quad" : "Dual", soc_dev_attr->family,
+ soc_dev_attr->soc_id, soc_dev_attr->revision,
+ npu_enabled ? " with Ethos-U55" : "");
+
+ /* Check CA55 PLL configuration */
+ if (FIELD_GET(SYS_LSI_MODE_STAT_BOOTPLLCA55, mode_val) != SYS_LSI_MODE_CA55_1_7GHZ)
+ dev_warn(dev, "CA55 PLL is not set to 1.7GHz\n");
+}
+
+static const struct rz_sysc_soc_id_init_data rzg3e_sys_soc_id_init_data __initconst = {
+ .family = "RZ/G3E",
+ .id = 0x8679447,
+ .devid_offset = 0x304,
+ .revision_mask = GENMASK(31, 28),
+ .specific_id_mask = GENMASK(27, 0),
+ .print_id = rzg3e_sys_print_id,
+};
+
+static bool rzg3e_regmap_readable_writeable_reg(unsigned int reg)
+{
+ switch (reg) {
+ case SYS_SPI_STAADDCS0:
+ case SYS_SPI_ENDADDCS0:
+ case SYS_SPI_STAADDCS1:
+ case SYS_SPI_ENDADDCS1:
+ case SYS_VSP_CLK:
+ case SYS_GBETH0_CFG:
+ case SYS_GBETH1_CFG:
+ case SYS_PCIE_INTX_CH0:
+ case SYS_PCIE_MSI1_CH0:
+ case SYS_PCIE_MSI2_CH0:
+ case SYS_PCIE_MSI3_CH0:
+ case SYS_PCIE_MSI4_CH0:
+ case SYS_PCIE_MSI5_CH0:
+ case SYS_PCIE_PME_CH0:
+ case SYS_PCIE_ACK_CH0:
+ case SYS_PCIE_MISC_CH0:
+ case SYS_PCIE_MODE_CH0:
+ case SYS_ADC_CFG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rzg3e_regmap_readable_reg(struct device *dev, unsigned int reg)
+{
+ if (rzg3e_regmap_readable_writeable_reg(reg))
+ return true;
+
+ switch (reg) {
+ case SYS_LSI_OTPTSU1TRMVAL0:
+ case SYS_LSI_OTPTSU1TRMVAL1:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rzg3e_regmap_writeable_reg(struct device *dev, unsigned int reg)
+{
+ return rzg3e_regmap_readable_writeable_reg(reg);
+}
+
+const struct rz_sysc_init_data rzg3e_sys_init_data __initconst = {
+ .soc_id_init_data = &rzg3e_sys_soc_id_init_data,
+ .readable_reg = rzg3e_regmap_readable_reg,
+ .writeable_reg = rzg3e_regmap_writeable_reg,
+ .max_register = 0x170c,
+};
diff --git a/drivers/soc/renesas/r9a09g056-sys.c b/drivers/soc/renesas/r9a09g056-sys.c
new file mode 100644
index 000000000..e6a666884
--- /dev/null
+++ b/drivers/soc/renesas/r9a09g056-sys.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/V2N System controller (SYS) driver
+ *
+ * Copyright (C) 2025 Renesas Electronics Corp.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include "rz-sysc.h"
+
+/* Register Offsets */
+#define SYS_LSI_MODE 0x300
+#define SYS_LSI_MODE_SEC_EN BIT(16)
+/*
+ * BOOTPLLCA[1:0]
+ * [0,0] => 1.1GHZ
+ * [0,1] => 1.5GHZ
+ * [1,0] => 1.6GHZ
+ * [1,1] => 1.7GHZ
+ */
+#define SYS_LSI_MODE_STAT_BOOTPLLCA55 GENMASK(12, 11)
+#define SYS_LSI_MODE_CA55_1_7GHZ 0x3
+
+#define SYS_LSI_PRR 0x308
+#define SYS_LSI_PRR_GPU_DIS BIT(0)
+#define SYS_LSI_PRR_ISP_DIS BIT(4)
+
+#define SYS_RZV2N_FEATURE_G31 BIT(0)
+#define SYS_RZV2N_FEATURE_C55 BIT(1)
+#define SYS_RZV2N_FEATURE_SEC BIT(2)
+
+#define SYS_LSI_OTPTSU0TRMVAL0 0x320
+#define SYS_LSI_OTPTSU0TRMVAL1 0x324
+#define SYS_LSI_OTPTSU1TRMVAL0 0x330
+#define SYS_LSI_OTPTSU1TRMVAL1 0x334
+#define SYS_GBETH0_CFG 0xf00
+#define SYS_GBETH1_CFG 0xf04
+#define SYS_PCIE_INTX_CH0 0x1000
+#define SYS_PCIE_MSI1_CH0 0x1004
+#define SYS_PCIE_MSI2_CH0 0x1008
+#define SYS_PCIE_MSI3_CH0 0x100c
+#define SYS_PCIE_MSI4_CH0 0x1010
+#define SYS_PCIE_MSI5_CH0 0x1014
+#define SYS_PCIE_PME_CH0 0x1018
+#define SYS_PCIE_ACK_CH0 0x101c
+#define SYS_PCIE_MISC_CH0 0x1020
+#define SYS_PCIE_MODE_CH0 0x1024
+#define SYS_ADC_CFG 0x1600
+
+static void rzv2n_sys_print_id(struct device *dev,
+ void __iomem *sysc_base,
+ struct soc_device_attribute *soc_dev_attr)
+{
+ u32 prr_val, mode_val;
+ u8 feature_flags;
+
+ prr_val = readl(sysc_base + SYS_LSI_PRR);
+ mode_val = readl(sysc_base + SYS_LSI_MODE);
+
+ /* Check GPU, ISP and Cryptographic configuration */
+ feature_flags = !(prr_val & SYS_LSI_PRR_GPU_DIS) ? SYS_RZV2N_FEATURE_G31 : 0;
+ feature_flags |= !(prr_val & SYS_LSI_PRR_ISP_DIS) ? SYS_RZV2N_FEATURE_C55 : 0;
+ feature_flags |= (mode_val & SYS_LSI_MODE_SEC_EN) ? SYS_RZV2N_FEATURE_SEC : 0;
+
+ dev_info(dev, "Detected Renesas %s %sn%d Rev %s%s%s%s%s\n", soc_dev_attr->family,
+ soc_dev_attr->soc_id, 41 + feature_flags, soc_dev_attr->revision,
+ feature_flags ? " with" : "",
+ feature_flags & SYS_RZV2N_FEATURE_G31 ? " GE3D (Mali-G31)" : "",
+ feature_flags & SYS_RZV2N_FEATURE_SEC ? " Cryptographic engine" : "",
+ feature_flags & SYS_RZV2N_FEATURE_C55 ? " ISP (Mali-C55)" : "");
+
+ /* Check CA55 PLL configuration */
+ if (FIELD_GET(SYS_LSI_MODE_STAT_BOOTPLLCA55, mode_val) != SYS_LSI_MODE_CA55_1_7GHZ)
+ dev_warn(dev, "CA55 PLL is not set to 1.7GHz\n");
+}
+
+static const struct rz_sysc_soc_id_init_data rzv2n_sys_soc_id_init_data __initconst = {
+ .family = "RZ/V2N",
+ .id = 0x867d447,
+ .devid_offset = 0x304,
+ .revision_mask = GENMASK(31, 28),
+ .specific_id_mask = GENMASK(27, 0),
+ .print_id = rzv2n_sys_print_id,
+};
+
+static bool rzv2n_regmap_readable_writeable_reg(unsigned int reg)
+{
+ switch (reg) {
+ case SYS_GBETH0_CFG:
+ case SYS_GBETH1_CFG:
+ case SYS_PCIE_INTX_CH0:
+ case SYS_PCIE_MSI1_CH0:
+ case SYS_PCIE_MSI2_CH0:
+ case SYS_PCIE_MSI3_CH0:
+ case SYS_PCIE_MSI4_CH0:
+ case SYS_PCIE_MSI5_CH0:
+ case SYS_PCIE_PME_CH0:
+ case SYS_PCIE_ACK_CH0:
+ case SYS_PCIE_MISC_CH0:
+ case SYS_PCIE_MODE_CH0:
+ case SYS_ADC_CFG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rzv2n_regmap_readable_reg(struct device *dev, unsigned int reg)
+{
+ if (rzv2n_regmap_readable_writeable_reg(reg))
+ return true;
+
+ switch (reg) {
+ case SYS_LSI_OTPTSU0TRMVAL0:
+ case SYS_LSI_OTPTSU0TRMVAL1:
+ case SYS_LSI_OTPTSU1TRMVAL0:
+ case SYS_LSI_OTPTSU1TRMVAL1:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rzv2n_regmap_writeable_reg(struct device *dev, unsigned int reg)
+{
+ return rzv2n_regmap_readable_writeable_reg(reg);
+}
+
+const struct rz_sysc_init_data rzv2n_sys_init_data __initconst = {
+ .soc_id_init_data = &rzv2n_sys_soc_id_init_data,
+ .readable_reg = rzv2n_regmap_readable_reg,
+ .writeable_reg = rzv2n_regmap_writeable_reg,
+ .max_register = 0x170c,
+};
diff --git a/drivers/soc/renesas/r9a09g057-sys.c b/drivers/soc/renesas/r9a09g057-sys.c
new file mode 100644
index 000000000..308492c31
--- /dev/null
+++ b/drivers/soc/renesas/r9a09g057-sys.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/V2H System controller (SYS) driver
+ *
+ * Copyright (C) 2025 Renesas Electronics Corp.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include "rz-sysc.h"
+
+/* Register Offsets */
+#define SYS_LSI_MODE 0x300
+/*
+ * BOOTPLLCA[1:0]
+ * [0,0] => 1.1GHZ
+ * [0,1] => 1.5GHZ
+ * [1,0] => 1.6GHZ
+ * [1,1] => 1.7GHZ
+ */
+#define SYS_LSI_MODE_STAT_BOOTPLLCA55 GENMASK(12, 11)
+#define SYS_LSI_MODE_CA55_1_7GHZ 0x3
+
+#define SYS_LSI_PRR 0x308
+#define SYS_LSI_PRR_GPU_DIS BIT(0)
+#define SYS_LSI_PRR_ISP_DIS BIT(4)
+
+#define SYS_LSI_OTPTSU0TRMVAL0 0x320
+#define SYS_LSI_OTPTSU0TRMVAL1 0x324
+#define SYS_LSI_OTPTSU1TRMVAL0 0x330
+#define SYS_LSI_OTPTSU1TRMVAL1 0x334
+#define SYS_GBETH0_CFG 0xf00
+#define SYS_GBETH1_CFG 0xf04
+#define SYS_PCIE_INTX_CH0 0x1000
+#define SYS_PCIE_MSI1_CH0 0x1004
+#define SYS_PCIE_MSI2_CH0 0x1008
+#define SYS_PCIE_MSI3_CH0 0x100c
+#define SYS_PCIE_MSI4_CH0 0x1010
+#define SYS_PCIE_MSI5_CH0 0x1014
+#define SYS_PCIE_PME_CH0 0x1018
+#define SYS_PCIE_ACK_CH0 0x101c
+#define SYS_PCIE_MISC_CH0 0x1020
+#define SYS_PCIE_MODE_CH0 0x1024
+#define SYS_PCIE_INTX_CH1 0x1030
+#define SYS_PCIE_MSI1_CH1 0x1034
+#define SYS_PCIE_MSI2_CH1 0x1038
+#define SYS_PCIE_MSI3_CH1 0x103c
+#define SYS_PCIE_MSI4_CH1 0x1040
+#define SYS_PCIE_MSI5_CH1 0x1044
+#define SYS_PCIE_PME_CH1 0x1048
+#define SYS_PCIE_ACK_CH1 0x104c
+#define SYS_PCIE_MISC_CH1 0x1050
+#define SYS_PCIE_MODE_CH1 0x1054
+#define SYS_PCIE_MODE 0x1060
+#define SYS_ADC_CFG 0x1600
+
+static void rzv2h_sys_print_id(struct device *dev,
+ void __iomem *sysc_base,
+ struct soc_device_attribute *soc_dev_attr)
+{
+ bool gpu_enabled, isp_enabled;
+ u32 prr_val, mode_val;
+
+ prr_val = readl(sysc_base + SYS_LSI_PRR);
+ mode_val = readl(sysc_base + SYS_LSI_MODE);
+
+ /* Check GPU and ISP configuration */
+ gpu_enabled = !(prr_val & SYS_LSI_PRR_GPU_DIS);
+ isp_enabled = !(prr_val & SYS_LSI_PRR_ISP_DIS);
+
+ dev_info(dev, "Detected Renesas %s %s Rev %s%s%s\n",
+ soc_dev_attr->family, soc_dev_attr->soc_id, soc_dev_attr->revision,
+ gpu_enabled ? " with GE3D (Mali-G31)" : "",
+ isp_enabled ? " with ISP (Mali-C55)" : "");
+
+ /* Check CA55 PLL configuration */
+ if (FIELD_GET(SYS_LSI_MODE_STAT_BOOTPLLCA55, mode_val) != SYS_LSI_MODE_CA55_1_7GHZ)
+ dev_warn(dev, "CA55 PLL is not set to 1.7GHz\n");
+}
+
+static const struct rz_sysc_soc_id_init_data rzv2h_sys_soc_id_init_data __initconst = {
+ .family = "RZ/V2H",
+ .id = 0x847a447,
+ .devid_offset = 0x304,
+ .revision_mask = GENMASK(31, 28),
+ .specific_id_mask = GENMASK(27, 0),
+ .print_id = rzv2h_sys_print_id,
+};
+
+static bool rzv2h_regmap_readable_writeable_reg(unsigned int reg)
+{
+ switch (reg) {
+ case SYS_GBETH0_CFG:
+ case SYS_GBETH1_CFG:
+ case SYS_PCIE_INTX_CH0:
+ case SYS_PCIE_MSI1_CH0:
+ case SYS_PCIE_MSI2_CH0:
+ case SYS_PCIE_MSI3_CH0:
+ case SYS_PCIE_MSI4_CH0:
+ case SYS_PCIE_MSI5_CH0:
+ case SYS_PCIE_PME_CH0:
+ case SYS_PCIE_ACK_CH0:
+ case SYS_PCIE_MISC_CH0:
+ case SYS_PCIE_MODE_CH0:
+ case SYS_PCIE_INTX_CH1:
+ case SYS_PCIE_MSI1_CH1:
+ case SYS_PCIE_MSI2_CH1:
+ case SYS_PCIE_MSI3_CH1:
+ case SYS_PCIE_MSI4_CH1:
+ case SYS_PCIE_MSI5_CH1:
+ case SYS_PCIE_PME_CH1:
+ case SYS_PCIE_ACK_CH1:
+ case SYS_PCIE_MISC_CH1:
+ case SYS_PCIE_MODE_CH1:
+ case SYS_PCIE_MODE:
+ case SYS_ADC_CFG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rzv2h_regmap_readable_reg(struct device *dev, unsigned int reg)
+{
+ if (rzv2h_regmap_readable_writeable_reg(reg))
+ return true;
+
+ switch (reg) {
+ case SYS_LSI_OTPTSU0TRMVAL0:
+ case SYS_LSI_OTPTSU0TRMVAL1:
+ case SYS_LSI_OTPTSU1TRMVAL0:
+ case SYS_LSI_OTPTSU1TRMVAL1:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rzv2h_regmap_writeable_reg(struct device *dev, unsigned int reg)
+{
+ return rzv2h_regmap_readable_writeable_reg(reg);
+}
+
+const struct rz_sysc_init_data rzv2h_sys_init_data __initconst = {
+ .soc_id_init_data = &rzv2h_sys_soc_id_init_data,
+ .readable_reg = rzv2h_regmap_readable_reg,
+ .writeable_reg = rzv2h_regmap_writeable_reg,
+ .max_register = 0x170c,
+};
diff --git a/drivers/soc/renesas/rcar-mfis.c b/drivers/soc/renesas/rcar-mfis.c
new file mode 100644
index 000000000..3435c3e16
--- /dev/null
+++ b/drivers/soc/renesas/rcar-mfis.c
@@ -0,0 +1,384 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Renesas R-Car MFIS (Multifunctional Interface) driver
+ *
+ * Copyright (C) Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ * Wolfram Sang <wsa+renesas@sang-engineering.com>
+ */
+#include <dt-bindings/soc/renesas,r8a78000-mfis.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mailbox_controller.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#define MFISWPCNTR 0x0900
+#define MFISWACNTR 0x0904
+
+#define MFIS_X5H_IICR(i) ((i) * 0x1000 + 0x00)
+#define MFIS_X5H_EICR(i) ((i) * 0x1000 + 0x04)
+
+#define MFIS_UNPROTECT_KEY 0xACCE0000
+
+struct mfis_priv;
+
+struct mfis_reg {
+ void __iomem *base;
+ resource_size_t start;
+ struct mfis_priv *priv;
+};
+
+struct mfis_info {
+ u32 unprotect_mask;
+ unsigned int mb_num_channels;
+ unsigned int mb_reg_comes_from_dt:1;
+ unsigned int mb_tx_uses_eicr:1;
+ unsigned int mb_channels_are_unidir:1;
+ u32 (*mb_calc_reg)(u32 chan_num, bool tx_uses_eicr, bool is_only_rx);
+};
+
+struct mfis_chan_priv {
+ u32 reg;
+ int irq;
+};
+
+struct mfis_priv {
+ spinlock_t unprotect_lock; /* guards access to the unprotection reg */
+ struct device *dev;
+ struct mfis_reg common_reg;
+ struct mfis_reg mbox_reg;
+ const struct mfis_info *info;
+
+ /* mailbox private data */
+ struct mbox_controller mbox;
+ struct mfis_chan_priv *chan_privs;
+};
+
+static u32 mfis_read(struct mfis_reg *mreg, unsigned int reg)
+{
+ return ioread32(mreg->base + reg);
+}
+
+static void mfis_write(struct mfis_reg *mreg, u32 reg, u32 val)
+{
+ struct mfis_priv *priv = mreg->priv;
+ u32 unprotect_mask = priv->info->unprotect_mask;
+ unsigned long flags;
+ u32 unprotect_code;
+
+ /*
+ * [Gen4] key: 0xACCE0000, mask: 0x0000FFFF
+ * [Gen5] key: 0xACC00000, mask: 0x000FFFFF
+ */
+ unprotect_code = (MFIS_UNPROTECT_KEY & ~unprotect_mask) |
+ ((mreg->start + reg) & unprotect_mask);
+
+ spin_lock_irqsave(&priv->unprotect_lock, flags);
+ iowrite32(unprotect_code, priv->common_reg.base + MFISWACNTR);
+ iowrite32(val, mreg->base + reg);
+ spin_unlock_irqrestore(&priv->unprotect_lock, flags);
+}
+
+/********************************************************
+ * Mailbox *
+ ********************************************************/
+
+#define mfis_mb_mbox_to_priv(_m) container_of((_m), struct mfis_priv, mbox)
+
+static irqreturn_t mfis_mb_iicr_interrupt(int irq, void *data)
+{
+ struct mbox_chan *chan = data;
+ struct mfis_priv *priv = mfis_mb_mbox_to_priv(chan->mbox);
+ struct mfis_chan_priv *chan_priv = chan->con_priv;
+
+ mbox_chan_received_data(chan, NULL);
+ /* Stop remote(!) doorbell */
+ mfis_write(&priv->mbox_reg, chan_priv->reg, 0);
+
+ return IRQ_HANDLED;
+}
+
+static int mfis_mb_startup(struct mbox_chan *chan)
+{
+ struct mfis_chan_priv *chan_priv = chan->con_priv;
+
+ if (!chan_priv->irq)
+ return 0;
+
+ return request_irq(chan_priv->irq, mfis_mb_iicr_interrupt, 0,
+ dev_name(chan->mbox->dev), chan);
+}
+
+static void mfis_mb_shutdown(struct mbox_chan *chan)
+{
+ struct mfis_chan_priv *chan_priv = chan->con_priv;
+
+ if (chan_priv->irq)
+ free_irq(chan_priv->irq, chan);
+}
+
+static int mfis_mb_iicr_send_data(struct mbox_chan *chan, void *data)
+{
+ struct mfis_priv *priv = mfis_mb_mbox_to_priv(chan->mbox);
+ struct mfis_chan_priv *chan_priv = chan->con_priv;
+
+ /* Our doorbell still active? */
+ if (mfis_read(&priv->mbox_reg, chan_priv->reg) & BIT(0))
+ return -EBUSY;
+
+ /* Start our doorbell */
+ mfis_write(&priv->mbox_reg, chan_priv->reg, BIT(0));
+
+ return 0;
+}
+
+static bool mfis_mb_iicr_last_tx_done(struct mbox_chan *chan)
+{
+ struct mfis_priv *priv = mfis_mb_mbox_to_priv(chan->mbox);
+ struct mfis_chan_priv *chan_priv = chan->con_priv;
+
+ /* Our doorbell still active? */
+ return !(mfis_read(&priv->mbox_reg, chan_priv->reg) & BIT(0));
+}
+
+/* For MFIS variants using the IICR/EICR register pair */
+static const struct mbox_chan_ops mfis_iicr_ops = {
+ .startup = mfis_mb_startup,
+ .shutdown = mfis_mb_shutdown,
+ .send_data = mfis_mb_iicr_send_data,
+ .last_tx_done = mfis_mb_iicr_last_tx_done,
+};
+
+static u32 mfis_mb_r8a779g0_calc_reg(u32 chan_num, bool tx_uses_eicr, bool is_only_rx)
+{
+ unsigned int i, k;
+ u32 reg;
+
+ i = chan_num & 3;
+ k = chan_num >> 2;
+
+ if (is_only_rx) {
+ if (k < 2)
+ reg = 0x9404 + 0x1020 * k + 0x08 * i;
+ else
+ reg = 0xb504 + 0x08 * i;
+ } else {
+ if (k < 2)
+ reg = 0x1400 + 0x1008 * i + 0x20 * k;
+ else
+ reg = 0x1500 + 0x1008 * i;
+ }
+
+ return reg;
+}
+
+static u32 mfis_mb_r8a78000_calc_reg(u32 chan_num, bool tx_uses_eicr, bool is_only_rx)
+{
+ return (tx_uses_eicr ^ is_only_rx) ? MFIS_X5H_EICR(chan_num) :
+ MFIS_X5H_IICR(chan_num);
+}
+
+static struct mbox_chan *mfis_mb_of_xlate(struct mbox_controller *mbox,
+ const struct of_phandle_args *sp)
+{
+ struct mfis_priv *priv = mfis_mb_mbox_to_priv(mbox);
+ struct mfis_chan_priv *chan_priv;
+ bool tx_uses_eicr, is_only_rx;
+ u32 chan_num, chan_flags;
+ struct mbox_chan *chan;
+
+ if (sp->args_count != 2)
+ return ERR_PTR(-EINVAL);
+
+ chan_num = sp->args[0];
+ chan_flags = sp->args[1];
+
+ if (chan_num >= priv->info->mb_num_channels)
+ return ERR_PTR(-EINVAL);
+
+ /* Channel layout is described in mfis_mb_probe() */
+ if (priv->info->mb_channels_are_unidir) {
+ is_only_rx = chan_flags & MFIS_CHANNEL_RX;
+ chan = mbox->chans + 2 * chan_num + is_only_rx;
+ } else {
+ is_only_rx = false;
+ chan = mbox->chans + chan_num;
+ }
+
+ if (priv->info->mb_reg_comes_from_dt) {
+ tx_uses_eicr = chan_flags & MFIS_CHANNEL_EICR;
+ if (tx_uses_eicr)
+ chan += mbox->num_chans / 2;
+ } else {
+ tx_uses_eicr = priv->info->mb_tx_uses_eicr;
+ }
+
+ chan_priv = chan->con_priv;
+ chan_priv->reg = priv->info->mb_calc_reg(chan_num, tx_uses_eicr, is_only_rx);
+
+ if (!priv->info->mb_channels_are_unidir || is_only_rx) {
+ char irqname[8];
+ char suffix = tx_uses_eicr ? 'i' : 'e';
+
+ /* "ch0i" or "ch0e" */
+ scnprintf(irqname, sizeof(irqname), "ch%u%c", chan_num, suffix);
+
+ chan_priv->irq = of_irq_get_byname(mbox->dev->of_node, irqname);
+ if (chan_priv->irq < 0)
+ return ERR_PTR(chan_priv->irq);
+ if (chan_priv->irq == 0)
+ return ERR_PTR(-ENOENT);
+ }
+
+ return chan;
+}
+
+static int mfis_mb_probe(struct mfis_priv *priv)
+{
+ unsigned int num_chan = priv->info->mb_num_channels;
+ struct device *dev = priv->dev;
+ struct mbox_controller *mbox;
+ struct mbox_chan *chan;
+
+ if (priv->info->mb_channels_are_unidir) {
+ /* Channel layout: Ch0-TX, Ch0-RX, Ch1-TX... */
+ num_chan *= 2;
+ }
+
+ if (priv->info->mb_reg_comes_from_dt) {
+ /* Channel layout: <n> IICR channels, <n> EICR channels */
+ num_chan *= 2;
+ }
+
+ chan = devm_kcalloc(dev, num_chan, sizeof(*chan), GFP_KERNEL);
+ if (!chan)
+ return -ENOMEM;
+
+ priv->chan_privs = devm_kcalloc(dev, num_chan, sizeof(*priv->chan_privs),
+ GFP_KERNEL);
+ if (!priv->chan_privs)
+ return -ENOMEM;
+
+ mbox = &priv->mbox;
+
+ for (unsigned int i = 0; i < num_chan; i++)
+ chan[i].con_priv = &priv->chan_privs[i];
+
+ mbox->chans = chan;
+ mbox->num_chans = num_chan;
+ mbox->txdone_poll = true;
+ mbox->ops = &mfis_iicr_ops;
+ mbox->dev = dev;
+ mbox->of_xlate = mfis_mb_of_xlate;
+
+ return devm_mbox_controller_register(dev, mbox);
+}
+
+/********************************************************
+ * Common *
+ ********************************************************/
+static int mfis_reg_probe(struct platform_device *pdev, struct mfis_priv *priv,
+ struct mfis_reg *mreg, const char *name, bool required)
+{
+ struct resource *res;
+ void __iomem *base;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+
+ /* If there is no mailbox resource, registers are in the common space */
+ if (!res && !required) {
+ *mreg = priv->common_reg;
+ } else {
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ mreg->base = base;
+ mreg->start = res->start;
+ mreg->priv = priv;
+ }
+
+ return 0;
+}
+
+static int mfis_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mfis_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+ priv->info = of_device_get_match_data(dev);
+ if (!priv->info)
+ return -ENOENT;
+
+ spin_lock_init(&priv->unprotect_lock);
+
+ ret = mfis_reg_probe(pdev, priv, &priv->common_reg, "common", true);
+ if (ret)
+ return ret;
+
+ ret = mfis_reg_probe(pdev, priv, &priv->mbox_reg, "mboxes", false);
+ if (ret)
+ return ret;
+
+ return mfis_mb_probe(priv);
+}
+
+static const struct mfis_info mfis_info_r8a779g0 = {
+ .unprotect_mask = 0x0000ffff,
+ .mb_num_channels = 12,
+ .mb_channels_are_unidir = true,
+ .mb_calc_reg = mfis_mb_r8a779g0_calc_reg,
+};
+
+static const struct mfis_info mfis_info_r8a78000 = {
+ .unprotect_mask = 0x000fffff,
+ .mb_num_channels = 64,
+ .mb_reg_comes_from_dt = true,
+ .mb_channels_are_unidir = true,
+ .mb_calc_reg = mfis_mb_r8a78000_calc_reg,
+};
+
+static const struct mfis_info mfis_info_r8a78000_scp = {
+ .unprotect_mask = 0x000fffff,
+ .mb_num_channels = 32,
+ .mb_tx_uses_eicr = true,
+ .mb_channels_are_unidir = true,
+ .mb_calc_reg = mfis_mb_r8a78000_calc_reg,
+};
+
+static const struct of_device_id mfis_mfd_of_match[] = {
+ { .compatible = "renesas,r8a779g0-mfis", .data = &mfis_info_r8a779g0, },
+ { .compatible = "renesas,r8a779h0-mfis", .data = &mfis_info_r8a779g0, },
+ { .compatible = "renesas,r8a78000-mfis", .data = &mfis_info_r8a78000, },
+ { .compatible = "renesas,r8a78000-mfis-scp", .data = &mfis_info_r8a78000_scp, },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mfis_mfd_of_match);
+
+static struct platform_driver mfis_driver = {
+ .driver = {
+ .name = "rcar-mfis",
+ .of_match_table = mfis_mfd_of_match,
+ .suppress_bind_attrs = true,
+ },
+ .probe = mfis_probe,
+};
+module_platform_driver(mfis_driver);
+
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+MODULE_AUTHOR("Wolfram Sang <wsa+renesas@sang-engineering.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Renesas R-Car MFIS driver");
diff --git a/drivers/soc/renesas/rcar-rst.c b/drivers/soc/renesas/rcar-rst.c
new file mode 100644
index 000000000..054199090
--- /dev/null
+++ b/drivers/soc/renesas/rcar-rst.c
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * R-Car Gen1 RESET/WDT, R-Car Gen2, Gen3, and RZ/G RST Driver
+ *
+ * Copyright (C) 2016 Glider bvba
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/soc/renesas/rcar-rst.h>
+
+#define WDTRSTCR_RESET 0xA55A0002
+#define WDTRSTCR 0x0054
+#define GEN4_WDTRSTCR_RESET 0xA55A8002
+#define GEN4_WDTRSTCR 0x0010
+
+#define CR7BAR 0x0070
+#define CR7BAREN BIT(4)
+#define CR7BAR_MASK 0xFFFC0000
+
+static void __iomem *rcar_rst_base;
+static u32 saved_mode __initdata;
+static int (*rcar_rst_set_rproc_boot_addr_func)(u64 boot_addr);
+
+static int rcar_rst_enable_wdt_reset(void __iomem *base)
+{
+ iowrite32(WDTRSTCR_RESET, base + WDTRSTCR);
+ return 0;
+}
+
+static int rcar_rst_v3u_enable_wdt_reset(void __iomem *base)
+{
+ iowrite32(GEN4_WDTRSTCR_RESET, base + GEN4_WDTRSTCR);
+ return 0;
+}
+
+/*
+ * Most of the R-Car Gen3 SoCs have an ARM Realtime Core.
+ * Firmware boot address has to be set in CR7BAR before
+ * starting the realtime core.
+ * Boot address must be aligned on a 256k boundary.
+ */
+static int rcar_rst_set_gen3_rproc_boot_addr(u64 boot_addr)
+{
+ if (boot_addr & ~(u64)CR7BAR_MASK) {
+ pr_err("Invalid boot address got %llx\n", boot_addr);
+ return -EINVAL;
+ }
+
+ iowrite32(boot_addr, rcar_rst_base + CR7BAR);
+ iowrite32(boot_addr | CR7BAREN, rcar_rst_base + CR7BAR);
+
+ return 0;
+}
+
+struct rst_config {
+ unsigned int modemr; /* Mode Monitoring Register Offset */
+ int (*configure)(void __iomem *base); /* Platform specific config */
+ int (*set_rproc_boot_addr)(u64 boot_addr);
+};
+
+static const struct rst_config rcar_rst_gen1 __initconst = {
+ .modemr = 0x20,
+};
+
+static const struct rst_config rcar_rst_gen2 __initconst = {
+ .modemr = 0x60,
+ .configure = rcar_rst_enable_wdt_reset,
+};
+
+static const struct rst_config rcar_rst_gen3 __initconst = {
+ .modemr = 0x60,
+ .set_rproc_boot_addr = rcar_rst_set_gen3_rproc_boot_addr,
+};
+
+/* V3U firmware doesn't enable WDT reset and there won't be updates anymore */
+static const struct rst_config rcar_rst_v3u __initconst = {
+ .modemr = 0x00, /* MODEMR0 and it has CPG related bits */
+ .configure = rcar_rst_v3u_enable_wdt_reset,
+};
+
+static const struct rst_config rcar_rst_gen4 __initconst = {
+ .modemr = 0x00, /* MODEMR0 and it has CPG related bits */
+};
+
+static const struct of_device_id rcar_rst_matches[] __initconst = {
+ /* RZ/G1 is handled like R-Car Gen2 */
+ { .compatible = "renesas,r8a7742-rst", .data = &rcar_rst_gen2 },
+ { .compatible = "renesas,r8a7743-rst", .data = &rcar_rst_gen2 },
+ { .compatible = "renesas,r8a7744-rst", .data = &rcar_rst_gen2 },
+ { .compatible = "renesas,r8a7745-rst", .data = &rcar_rst_gen2 },
+ { .compatible = "renesas,r8a77470-rst", .data = &rcar_rst_gen2 },
+ /* RZ/G2 is handled like R-Car Gen3 */
+ { .compatible = "renesas,r8a774a1-rst", .data = &rcar_rst_gen3 },
+ { .compatible = "renesas,r8a774b1-rst", .data = &rcar_rst_gen3 },
+ { .compatible = "renesas,r8a774c0-rst", .data = &rcar_rst_gen3 },
+ { .compatible = "renesas,r8a774e1-rst", .data = &rcar_rst_gen3 },
+ /* R-Car Gen1 */
+ { .compatible = "renesas,r8a7778-reset-wdt", .data = &rcar_rst_gen1 },
+ { .compatible = "renesas,r8a7779-reset-wdt", .data = &rcar_rst_gen1 },
+ /* R-Car Gen2 */
+ { .compatible = "renesas,r8a7790-rst", .data = &rcar_rst_gen2 },
+ { .compatible = "renesas,r8a7791-rst", .data = &rcar_rst_gen2 },
+ { .compatible = "renesas,r8a7792-rst", .data = &rcar_rst_gen2 },
+ { .compatible = "renesas,r8a7793-rst", .data = &rcar_rst_gen2 },
+ { .compatible = "renesas,r8a7794-rst", .data = &rcar_rst_gen2 },
+ /* R-Car Gen3 */
+ { .compatible = "renesas,r8a7795-rst", .data = &rcar_rst_gen3 },
+ { .compatible = "renesas,r8a7796-rst", .data = &rcar_rst_gen3 },
+ { .compatible = "renesas,r8a77961-rst", .data = &rcar_rst_gen3 },
+ { .compatible = "renesas,r8a77965-rst", .data = &rcar_rst_gen3 },
+ { .compatible = "renesas,r8a77970-rst", .data = &rcar_rst_gen3 },
+ { .compatible = "renesas,r8a77980-rst", .data = &rcar_rst_gen3 },
+ { .compatible = "renesas,r8a77990-rst", .data = &rcar_rst_gen3 },
+ { .compatible = "renesas,r8a77995-rst", .data = &rcar_rst_gen3 },
+ /* R-Car Gen4 */
+ { .compatible = "renesas,r8a779a0-rst", .data = &rcar_rst_v3u },
+ { .compatible = "renesas,r8a779f0-rst", .data = &rcar_rst_gen4 },
+ { .compatible = "renesas,r8a779g0-rst", .data = &rcar_rst_gen4 },
+ { .compatible = "renesas,r8a779h0-rst", .data = &rcar_rst_gen4 },
+ { /* sentinel */ }
+};
+
+static int __init rcar_rst_init(void)
+{
+ const struct of_device_id *match;
+ const struct rst_config *cfg;
+ struct device_node *np;
+ void __iomem *base;
+ int error = 0;
+
+ np = of_find_matching_node_and_match(NULL, rcar_rst_matches, &match);
+ if (!np)
+ return -ENODEV;
+
+ base = of_iomap(np, 0);
+ if (!base) {
+ pr_warn("%pOF: Cannot map regs\n", np);
+ error = -ENOMEM;
+ goto out_put;
+ }
+
+ rcar_rst_base = base;
+ cfg = match->data;
+ rcar_rst_set_rproc_boot_addr_func = cfg->set_rproc_boot_addr;
+
+ saved_mode = ioread32(base + cfg->modemr);
+ if (cfg->configure) {
+ error = cfg->configure(base);
+ if (error) {
+ pr_warn("%pOF: Cannot run SoC specific configuration\n",
+ np);
+ goto out_put;
+ }
+ }
+
+ pr_debug("%pOF: MODE = 0x%08x\n", np, saved_mode);
+
+out_put:
+ of_node_put(np);
+ return error;
+}
+
+int __init rcar_rst_read_mode_pins(u32 *mode)
+{
+ int error;
+
+ if (!rcar_rst_base) {
+ error = rcar_rst_init();
+ if (error)
+ return error;
+ }
+
+ *mode = saved_mode;
+ return 0;
+}
+
+int rcar_rst_set_rproc_boot_addr(u64 boot_addr)
+{
+ if (!rcar_rst_set_rproc_boot_addr_func)
+ return -EIO;
+
+ return rcar_rst_set_rproc_boot_addr_func(boot_addr);
+}
+EXPORT_SYMBOL_GPL(rcar_rst_set_rproc_boot_addr);
diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c
new file mode 100644
index 000000000..18acca730
--- /dev/null
+++ b/drivers/soc/renesas/renesas-soc.c
@@ -0,0 +1,560 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas SoC Identification
+ *
+ * Copyright (C) 2014-2016 Glider bvba
+ */
+
+#include <linux/bitfield.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/sys_soc.h>
+
+struct renesas_family {
+ const char name[16];
+ u32 reg; /* CCCR or PRR, if not in DT */
+};
+
+static const struct renesas_family fam_rcar_gen1 __initconst __maybe_unused = {
+ .name = "R-Car Gen1",
+ .reg = 0xff000044, /* PRR (Product Register) */
+};
+
+static const struct renesas_family fam_rcar_gen2 __initconst __maybe_unused = {
+ .name = "R-Car Gen2",
+ .reg = 0xff000044, /* PRR (Product Register) */
+};
+
+static const struct renesas_family fam_rcar_gen3 __initconst __maybe_unused = {
+ .name = "R-Car Gen3",
+ .reg = 0xfff00044, /* PRR (Product Register) */
+};
+
+static const struct renesas_family fam_rcar_gen4 __initconst __maybe_unused = {
+ .name = "R-Car Gen4",
+};
+
+static const struct renesas_family fam_rcar_gen5 __initconst __maybe_unused = {
+ .name = "R-Car Gen5",
+};
+
+static const struct renesas_family fam_rmobile __initconst __maybe_unused = {
+ .name = "R-Mobile",
+ .reg = 0xe600101c, /* CCCR (Common Chip Code Register) */
+};
+
+static const struct renesas_family fam_rza1 __initconst __maybe_unused = {
+ .name = "RZ/A1",
+};
+
+static const struct renesas_family fam_rza2 __initconst __maybe_unused = {
+ .name = "RZ/A2",
+};
+
+static const struct renesas_family fam_rzfive __initconst __maybe_unused = {
+ .name = "RZ/Five",
+};
+
+static const struct renesas_family fam_rzg1 __initconst __maybe_unused = {
+ .name = "RZ/G1",
+ .reg = 0xff000044, /* PRR (Product Register) */
+};
+
+static const struct renesas_family fam_rzg2 __initconst __maybe_unused = {
+ .name = "RZ/G2",
+ .reg = 0xfff00044, /* PRR (Product Register) */
+};
+
+static const struct renesas_family fam_rzg2l __initconst __maybe_unused = {
+ .name = "RZ/G2L",
+};
+
+static const struct renesas_family fam_rzg2ul __initconst __maybe_unused = {
+ .name = "RZ/G2UL",
+};
+
+static const struct renesas_family fam_rzv2l __initconst __maybe_unused = {
+ .name = "RZ/V2L",
+};
+
+static const struct renesas_family fam_rzv2m __initconst __maybe_unused = {
+ .name = "RZ/V2M",
+};
+
+static const struct renesas_family fam_shmobile __initconst __maybe_unused = {
+ .name = "SH-Mobile",
+ .reg = 0xe600101c, /* CCCR (Common Chip Code Register) */
+};
+
+struct renesas_soc {
+ const struct renesas_family *family;
+ u32 id;
+};
+
+static const struct renesas_soc soc_rz_a1h __initconst __maybe_unused = {
+ .family = &fam_rza1,
+};
+
+static const struct renesas_soc soc_rz_a2m __initconst __maybe_unused = {
+ .family = &fam_rza2,
+ .id = 0x3b,
+};
+
+static const struct renesas_soc soc_rmobile_ape6 __initconst __maybe_unused = {
+ .family = &fam_rmobile,
+ .id = 0x3f,
+};
+
+static const struct renesas_soc soc_rmobile_a1 __initconst __maybe_unused = {
+ .family = &fam_rmobile,
+ .id = 0x40,
+};
+
+static const struct renesas_soc soc_rz_five __initconst __maybe_unused = {
+ .family = &fam_rzfive,
+ .id = 0x847c447,
+};
+
+static const struct renesas_soc soc_rz_g1h __initconst __maybe_unused = {
+ .family = &fam_rzg1,
+ .id = 0x45,
+};
+
+static const struct renesas_soc soc_rz_g1m __initconst __maybe_unused = {
+ .family = &fam_rzg1,
+ .id = 0x47,
+};
+
+static const struct renesas_soc soc_rz_g1n __initconst __maybe_unused = {
+ .family = &fam_rzg1,
+ .id = 0x4b,
+};
+
+static const struct renesas_soc soc_rz_g1e __initconst __maybe_unused = {
+ .family = &fam_rzg1,
+ .id = 0x4c,
+};
+
+static const struct renesas_soc soc_rz_g1c __initconst __maybe_unused = {
+ .family = &fam_rzg1,
+ .id = 0x53,
+};
+
+static const struct renesas_soc soc_rz_g2m __initconst __maybe_unused = {
+ .family = &fam_rzg2,
+ .id = 0x52,
+};
+
+static const struct renesas_soc soc_rz_g2n __initconst __maybe_unused = {
+ .family = &fam_rzg2,
+ .id = 0x55,
+};
+
+static const struct renesas_soc soc_rz_g2e __initconst __maybe_unused = {
+ .family = &fam_rzg2,
+ .id = 0x57,
+};
+
+static const struct renesas_soc soc_rz_g2h __initconst __maybe_unused = {
+ .family = &fam_rzg2,
+ .id = 0x4f,
+};
+
+static const struct renesas_soc soc_rz_g2l __initconst __maybe_unused = {
+ .family = &fam_rzg2l,
+ .id = 0x841c447,
+};
+
+static const struct renesas_soc soc_rz_g2ul __initconst __maybe_unused = {
+ .family = &fam_rzg2ul,
+ .id = 0x8450447,
+};
+
+static const struct renesas_soc soc_rz_v2l __initconst __maybe_unused = {
+ .family = &fam_rzv2l,
+ .id = 0x8447447,
+};
+
+static const struct renesas_soc soc_rz_v2m __initconst __maybe_unused = {
+ .family = &fam_rzv2m,
+};
+
+static const struct renesas_soc soc_rcar_m1a __initconst __maybe_unused = {
+ .family = &fam_rcar_gen1,
+};
+
+static const struct renesas_soc soc_rcar_h1 __initconst __maybe_unused = {
+ .family = &fam_rcar_gen1,
+ .id = 0x3b,
+};
+
+static const struct renesas_soc soc_rcar_h2 __initconst __maybe_unused = {
+ .family = &fam_rcar_gen2,
+ .id = 0x45,
+};
+
+static const struct renesas_soc soc_rcar_m2_w __initconst __maybe_unused = {
+ .family = &fam_rcar_gen2,
+ .id = 0x47,
+};
+
+static const struct renesas_soc soc_rcar_v2h __initconst __maybe_unused = {
+ .family = &fam_rcar_gen2,
+ .id = 0x4a,
+};
+
+static const struct renesas_soc soc_rcar_m2_n __initconst __maybe_unused = {
+ .family = &fam_rcar_gen2,
+ .id = 0x4b,
+};
+
+static const struct renesas_soc soc_rcar_e2 __initconst __maybe_unused = {
+ .family = &fam_rcar_gen2,
+ .id = 0x4c,
+};
+
+static const struct renesas_soc soc_rcar_h3 __initconst __maybe_unused = {
+ .family = &fam_rcar_gen3,
+ .id = 0x4f,
+};
+
+static const struct renesas_soc soc_rcar_m3_w __initconst __maybe_unused = {
+ .family = &fam_rcar_gen3,
+ .id = 0x52,
+};
+
+static const struct renesas_soc soc_rcar_m3_n __initconst __maybe_unused = {
+ .family = &fam_rcar_gen3,
+ .id = 0x55,
+};
+
+static const struct renesas_soc soc_rcar_v3m __initconst __maybe_unused = {
+ .family = &fam_rcar_gen3,
+ .id = 0x54,
+};
+
+static const struct renesas_soc soc_rcar_v3h __initconst __maybe_unused = {
+ .family = &fam_rcar_gen3,
+ .id = 0x56,
+};
+
+static const struct renesas_soc soc_rcar_e3 __initconst __maybe_unused = {
+ .family = &fam_rcar_gen3,
+ .id = 0x57,
+};
+
+static const struct renesas_soc soc_rcar_d3 __initconst __maybe_unused = {
+ .family = &fam_rcar_gen3,
+ .id = 0x58,
+};
+
+static const struct renesas_soc soc_rcar_v3u __initconst __maybe_unused = {
+ .family = &fam_rcar_gen4,
+ .id = 0x59,
+};
+
+static const struct renesas_soc soc_rcar_s4 __initconst __maybe_unused = {
+ .family = &fam_rcar_gen4,
+ .id = 0x5a,
+};
+
+static const struct renesas_soc soc_rcar_v4h __initconst __maybe_unused = {
+ .family = &fam_rcar_gen4,
+ .id = 0x5c,
+};
+
+static const struct renesas_soc soc_rcar_v4m __initconst __maybe_unused = {
+ .family = &fam_rcar_gen4,
+ .id = 0x5d,
+};
+
+static const struct renesas_soc soc_rcar_x5h __initconst __maybe_unused = {
+ .family = &fam_rcar_gen5,
+ .id = 0x60,
+};
+
+static const struct renesas_soc soc_shmobile_ag5 __initconst __maybe_unused = {
+ .family = &fam_shmobile,
+ .id = 0x37,
+};
+
+static const struct of_device_id renesas_socs[] __initconst __maybe_unused = {
+#ifdef CONFIG_ARCH_R7S72100
+ { .compatible = "renesas,r7s72100", .data = &soc_rz_a1h },
+#endif
+#ifdef CONFIG_ARCH_R7S9210
+ { .compatible = "renesas,r7s9210", .data = &soc_rz_a2m },
+#endif
+#ifdef CONFIG_ARCH_R8A73A4
+ { .compatible = "renesas,r8a73a4", .data = &soc_rmobile_ape6 },
+#endif
+#ifdef CONFIG_ARCH_R8A7740
+ { .compatible = "renesas,r8a7740", .data = &soc_rmobile_a1 },
+#endif
+#ifdef CONFIG_ARCH_R8A7742
+ { .compatible = "renesas,r8a7742", .data = &soc_rz_g1h },
+#endif
+#ifdef CONFIG_ARCH_R8A7743
+ { .compatible = "renesas,r8a7743", .data = &soc_rz_g1m },
+#endif
+#ifdef CONFIG_ARCH_R8A7744
+ { .compatible = "renesas,r8a7744", .data = &soc_rz_g1n },
+#endif
+#ifdef CONFIG_ARCH_R8A7745
+ { .compatible = "renesas,r8a7745", .data = &soc_rz_g1e },
+#endif
+#ifdef CONFIG_ARCH_R8A77470
+ { .compatible = "renesas,r8a77470", .data = &soc_rz_g1c },
+#endif
+#ifdef CONFIG_ARCH_R8A774A1
+ { .compatible = "renesas,r8a774a1", .data = &soc_rz_g2m },
+#endif
+#ifdef CONFIG_ARCH_R8A774B1
+ { .compatible = "renesas,r8a774b1", .data = &soc_rz_g2n },
+#endif
+#ifdef CONFIG_ARCH_R8A774C0
+ { .compatible = "renesas,r8a774c0", .data = &soc_rz_g2e },
+#endif
+#ifdef CONFIG_ARCH_R8A774E1
+ { .compatible = "renesas,r8a774e1", .data = &soc_rz_g2h },
+#endif
+#ifdef CONFIG_ARCH_R8A7778
+ { .compatible = "renesas,r8a7778", .data = &soc_rcar_m1a },
+#endif
+#ifdef CONFIG_ARCH_R8A7779
+ { .compatible = "renesas,r8a7779", .data = &soc_rcar_h1 },
+#endif
+#ifdef CONFIG_ARCH_R8A7790
+ { .compatible = "renesas,r8a7790", .data = &soc_rcar_h2 },
+#endif
+#ifdef CONFIG_ARCH_R8A7791
+ { .compatible = "renesas,r8a7791", .data = &soc_rcar_m2_w },
+#endif
+#ifdef CONFIG_ARCH_R8A7792
+ { .compatible = "renesas,r8a7792", .data = &soc_rcar_v2h },
+#endif
+#ifdef CONFIG_ARCH_R8A7793
+ { .compatible = "renesas,r8a7793", .data = &soc_rcar_m2_n },
+#endif
+#ifdef CONFIG_ARCH_R8A7794
+ { .compatible = "renesas,r8a7794", .data = &soc_rcar_e2 },
+#endif
+#ifdef CONFIG_ARCH_R8A77951
+ { .compatible = "renesas,r8a7795", .data = &soc_rcar_h3 },
+ { .compatible = "renesas,r8a779m0", .data = &soc_rcar_h3 },
+ { .compatible = "renesas,r8a779m1", .data = &soc_rcar_h3 },
+ { .compatible = "renesas,r8a779m8", .data = &soc_rcar_h3 },
+ { .compatible = "renesas,r8a779mb", .data = &soc_rcar_h3 },
+#endif
+#ifdef CONFIG_ARCH_R8A77960
+ { .compatible = "renesas,r8a7796", .data = &soc_rcar_m3_w },
+#endif
+#ifdef CONFIG_ARCH_R8A77961
+ { .compatible = "renesas,r8a77961", .data = &soc_rcar_m3_w },
+ { .compatible = "renesas,r8a779m2", .data = &soc_rcar_m3_w },
+ { .compatible = "renesas,r8a779m3", .data = &soc_rcar_m3_w },
+#endif
+#ifdef CONFIG_ARCH_R8A77965
+ { .compatible = "renesas,r8a77965", .data = &soc_rcar_m3_n },
+ { .compatible = "renesas,r8a779m4", .data = &soc_rcar_m3_n },
+ { .compatible = "renesas,r8a779m5", .data = &soc_rcar_m3_n },
+ { .compatible = "renesas,r8a779md", .data = &soc_rcar_m3_n },
+#endif
+#ifdef CONFIG_ARCH_R8A77970
+ { .compatible = "renesas,r8a77970", .data = &soc_rcar_v3m },
+#endif
+#ifdef CONFIG_ARCH_R8A77980
+ { .compatible = "renesas,r8a77980", .data = &soc_rcar_v3h },
+#endif
+#ifdef CONFIG_ARCH_R8A77990
+ { .compatible = "renesas,r8a77990", .data = &soc_rcar_e3 },
+ { .compatible = "renesas,r8a779m6", .data = &soc_rcar_e3 },
+#endif
+#ifdef CONFIG_ARCH_R8A77995
+ { .compatible = "renesas,r8a77995", .data = &soc_rcar_d3 },
+ { .compatible = "renesas,r8a779m7", .data = &soc_rcar_d3 },
+#endif
+#ifdef CONFIG_ARCH_R8A779A0
+ { .compatible = "renesas,r8a779a0", .data = &soc_rcar_v3u },
+#endif
+#ifdef CONFIG_ARCH_R8A779F0
+ { .compatible = "renesas,r8a779f0", .data = &soc_rcar_s4 },
+#endif
+#ifdef CONFIG_ARCH_R8A779G0
+ { .compatible = "renesas,r8a779g0", .data = &soc_rcar_v4h },
+#endif
+#ifdef CONFIG_ARCH_R8A779H0
+ { .compatible = "renesas,r8a779h0", .data = &soc_rcar_v4m },
+#endif
+#ifdef CONFIG_ARCH_R8A78000
+ { .compatible = "renesas,r8a78000", .data = &soc_rcar_x5h },
+#endif
+#ifdef CONFIG_ARCH_R9A07G043
+#ifdef CONFIG_RISCV
+ { .compatible = "renesas,r9a07g043", .data = &soc_rz_five },
+#else
+ { .compatible = "renesas,r9a07g043", .data = &soc_rz_g2ul },
+#endif
+#endif
+#ifdef CONFIG_ARCH_R9A07G044
+ { .compatible = "renesas,r9a07g044", .data = &soc_rz_g2l },
+#endif
+#ifdef CONFIG_ARCH_R9A07G054
+ { .compatible = "renesas,r9a07g054", .data = &soc_rz_v2l },
+#endif
+#ifdef CONFIG_ARCH_R9A09G011
+ { .compatible = "renesas,r9a09g011", .data = &soc_rz_v2m },
+#endif
+#ifdef CONFIG_ARCH_SH73A0
+ { .compatible = "renesas,sh73a0", .data = &soc_shmobile_ag5 },
+#endif
+ { /* sentinel */ }
+};
+
+struct renesas_id {
+ unsigned int offset;
+ u32 mask;
+};
+
+static const struct renesas_id id_bsid __initconst = {
+ .offset = 0,
+ .mask = 0xff0000,
+ /*
+ * TODO: Upper 4 bits of BSID are for chip version, but the format is
+ * not known at this time so we don't know how to specify eshi and eslo
+ */
+};
+
+static const struct renesas_id id_rzg2l __initconst = {
+ .offset = 0xa04,
+ .mask = 0xfffffff,
+};
+
+static const struct renesas_id id_rzv2m __initconst = {
+ .offset = 0x104,
+ .mask = 0xff,
+};
+
+static const struct renesas_id id_prr __initconst = {
+ .offset = 0,
+ .mask = 0xff00,
+};
+
+static const struct renesas_id id_mfis __initconst = {
+ .offset = 0x44,
+ .mask = 0xff00,
+};
+
+static const struct of_device_id renesas_ids[] __initconst = {
+ { .compatible = "renesas,bsid", .data = &id_bsid },
+ { .compatible = "renesas,r8a78000-mfis", .data = &id_mfis },
+ { .compatible = "renesas,r9a07g043-sysc", .data = &id_rzg2l },
+ { .compatible = "renesas,r9a07g044-sysc", .data = &id_rzg2l },
+ { .compatible = "renesas,r9a07g054-sysc", .data = &id_rzg2l },
+ { .compatible = "renesas,r9a08g045-sysc", .data = &id_rzg2l },
+ { .compatible = "renesas,r9a09g011-sys", .data = &id_rzv2m },
+ { .compatible = "renesas,prr", .data = &id_prr },
+ { /* sentinel */ }
+};
+
+static int __init renesas_soc_init(void)
+{
+ struct soc_device_attribute *soc_dev_attr;
+ unsigned int product, eshi = 0, eslo;
+ const struct renesas_family *family;
+ const struct of_device_id *match;
+ const struct renesas_soc *soc;
+ const struct renesas_id *id;
+ void __iomem *chipid = NULL;
+ const char *rev_prefix = "";
+ struct soc_device *soc_dev;
+ struct device_node *np;
+ const char *soc_id;
+ int ret;
+
+ match = of_machine_get_match(renesas_socs);
+ if (!match)
+ return -ENODEV;
+
+ soc_id = strchr(match->compatible, ',') + 1;
+ soc = match->data;
+ family = soc->family;
+
+ np = of_find_matching_node_and_match(NULL, renesas_ids, &match);
+ if (np) {
+ id = match->data;
+ chipid = of_iomap(np, 0);
+ of_node_put(np);
+ } else if (soc->id && family->reg) {
+ /* Try hardcoded CCCR/PRR fallback */
+ id = &id_prr;
+ chipid = ioremap(family->reg, 4);
+ }
+
+ soc_dev_attr = kzalloc_obj(*soc_dev_attr);
+ if (!soc_dev_attr) {
+ if (chipid)
+ iounmap(chipid);
+ return -ENOMEM;
+ }
+
+ soc_dev_attr->family = kstrdup_const(family->name, GFP_KERNEL);
+ soc_dev_attr->soc_id = kstrdup_const(soc_id, GFP_KERNEL);
+
+ if (chipid) {
+ product = readl(chipid + id->offset);
+ iounmap(chipid);
+
+ if (id == &id_prr || id == &id_mfis) {
+ /* R-Car M3-W ES1.1 incorrectly identifies as ES2.0 */
+ if ((product & 0x7fff) == 0x5210)
+ product ^= 0x11;
+ /* R-Car M3-W ES1.3 incorrectly identifies as ES2.1 */
+ if ((product & 0x7fff) == 0x5211)
+ product ^= 0x12;
+
+ eshi = ((product >> 4) & 0x0f) + 1;
+ eslo = product & 0xf;
+ soc_dev_attr->revision = kasprintf(GFP_KERNEL, "ES%u.%u",
+ eshi, eslo);
+ } else if (id == &id_rzg2l) {
+ eshi = ((product >> 28) & 0x0f);
+ soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%u",
+ eshi);
+ rev_prefix = "Rev ";
+ } else if (id == &id_rzv2m) {
+ eshi = ((product >> 4) & 0x0f);
+ eslo = product & 0xf;
+ soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%u.%u",
+ eshi, eslo);
+ }
+
+ if (soc->id && field_get(id->mask, product) != soc->id) {
+ pr_warn("SoC mismatch (product = 0x%x)\n", product);
+ ret = -ENODEV;
+ goto free_soc_dev_attr;
+ }
+ }
+
+ pr_info("Detected Renesas %s %s %s%s\n", soc_dev_attr->family,
+ soc_dev_attr->soc_id, rev_prefix, soc_dev_attr->revision ?: "");
+
+ soc_dev = soc_device_register(soc_dev_attr);
+ if (IS_ERR(soc_dev)) {
+ ret = PTR_ERR(soc_dev);
+ goto free_soc_dev_attr;
+ }
+
+ return 0;
+
+free_soc_dev_attr:
+ kfree(soc_dev_attr->revision);
+ kfree_const(soc_dev_attr->soc_id);
+ kfree_const(soc_dev_attr->family);
+ kfree(soc_dev_attr);
+ return ret;
+}
+early_initcall(renesas_soc_init);
diff --git a/drivers/soc/renesas/rz-sysc.c b/drivers/soc/renesas/rz-sysc.c
new file mode 100644
index 000000000..161e8c38e
--- /dev/null
+++ b/drivers/soc/renesas/rz-sysc.c
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ System controller driver
+ *
+ * Copyright (C) 2024 Renesas Electronics Corp.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/sys_soc.h>
+
+#include "rz-sysc.h"
+
+/**
+ * struct rz_sysc - RZ SYSC private data structure
+ * @base: SYSC base address
+ * @dev: SYSC device pointer
+ */
+struct rz_sysc {
+ void __iomem *base;
+ struct device *dev;
+};
+
+static int rz_sysc_soc_init(struct rz_sysc *sysc, const struct of_device_id *match)
+{
+ const struct rz_sysc_init_data *sysc_data = match->data;
+ const struct rz_sysc_soc_id_init_data *soc_data = sysc_data->soc_id_init_data;
+ struct soc_device_attribute *soc_dev_attr;
+ const char *soc_id_start, *soc_id_end;
+ u32 val, revision, specific_id;
+ struct soc_device *soc_dev;
+ char soc_id[32] = {0};
+ size_t size;
+
+ soc_id_start = strchr(match->compatible, ',') + 1;
+ soc_id_end = strchr(match->compatible, '-');
+ size = soc_id_end - soc_id_start + 1;
+ if (size > 32)
+ size = sizeof(soc_id);
+ strscpy(soc_id, soc_id_start, size);
+
+ soc_dev_attr = devm_kzalloc(sysc->dev, sizeof(*soc_dev_attr), GFP_KERNEL);
+ if (!soc_dev_attr)
+ return -ENOMEM;
+
+ soc_dev_attr->family = devm_kstrdup(sysc->dev, soc_data->family, GFP_KERNEL);
+ if (!soc_dev_attr->family)
+ return -ENOMEM;
+
+ soc_dev_attr->soc_id = devm_kstrdup(sysc->dev, soc_id, GFP_KERNEL);
+ if (!soc_dev_attr->soc_id)
+ return -ENOMEM;
+
+ val = readl(sysc->base + soc_data->devid_offset);
+ revision = field_get(soc_data->revision_mask, val);
+ specific_id = field_get(soc_data->specific_id_mask, val);
+ soc_dev_attr->revision = devm_kasprintf(sysc->dev, GFP_KERNEL, "%u", revision);
+ if (!soc_dev_attr->revision)
+ return -ENOMEM;
+
+ if (soc_data->id && specific_id != soc_data->id) {
+ dev_warn(sysc->dev, "SoC mismatch (product = 0x%x)\n", specific_id);
+ return -ENODEV;
+ }
+
+ /* Try to call SoC-specific device identification */
+ if (soc_data->print_id) {
+ soc_data->print_id(sysc->dev, sysc->base, soc_dev_attr);
+ } else {
+ dev_info(sysc->dev, "Detected Renesas %s %s Rev %s\n",
+ soc_dev_attr->family, soc_dev_attr->soc_id, soc_dev_attr->revision);
+ }
+
+ soc_dev = soc_device_register(soc_dev_attr);
+ if (IS_ERR(soc_dev))
+ return PTR_ERR(soc_dev);
+
+ return 0;
+}
+
+static const struct of_device_id rz_sysc_match[] = {
+#ifdef CONFIG_SYSC_R9A08G045
+ { .compatible = "renesas,r9a08g045-sysc", .data = &rzg3s_sysc_init_data },
+#endif
+#ifdef CONFIG_SYSC_R9A08G046
+ { .compatible = "renesas,r9a08g046-sysc", .data = &rzg3l_sysc_init_data },
+#endif
+#ifdef CONFIG_SYS_R9A09G047
+ { .compatible = "renesas,r9a09g047-sys", .data = &rzg3e_sys_init_data },
+#endif
+#ifdef CONFIG_SYS_R9A09G056
+ { .compatible = "renesas,r9a09g056-sys", .data = &rzv2n_sys_init_data },
+#endif
+#ifdef CONFIG_SYS_R9A09G057
+ { .compatible = "renesas,r9a09g057-sys", .data = &rzv2h_sys_init_data },
+#endif
+ { }
+};
+MODULE_DEVICE_TABLE(of, rz_sysc_match);
+
+static int rz_sysc_probe(struct platform_device *pdev)
+{
+ const struct rz_sysc_init_data *data;
+ const struct of_device_id *match;
+ struct device *dev = &pdev->dev;
+ struct regmap *regmap;
+ struct rz_sysc *sysc;
+ int ret;
+
+ struct regmap_config *regmap_cfg __free(kfree) = kzalloc_obj(*regmap_cfg);
+ if (!regmap_cfg)
+ return -ENOMEM;
+
+ match = of_match_node(rz_sysc_match, dev->of_node);
+ if (!match)
+ return -ENODEV;
+
+ data = match->data;
+
+ sysc = devm_kzalloc(dev, sizeof(*sysc), GFP_KERNEL);
+ if (!sysc)
+ return -ENOMEM;
+
+ sysc->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(sysc->base))
+ return PTR_ERR(sysc->base);
+
+ sysc->dev = dev;
+ ret = rz_sysc_soc_init(sysc, match);
+ if (ret)
+ return ret;
+
+ regmap_cfg->name = "rz_sysc_regs";
+ regmap_cfg->reg_bits = 32;
+ regmap_cfg->reg_stride = 4;
+ regmap_cfg->val_bits = 32;
+ regmap_cfg->fast_io = true;
+ regmap_cfg->max_register = data->max_register;
+ regmap_cfg->readable_reg = data->readable_reg;
+ regmap_cfg->writeable_reg = data->writeable_reg;
+
+ regmap = devm_regmap_init_mmio(dev, sysc->base, regmap_cfg);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return of_syscon_register_regmap(dev->of_node, regmap);
+}
+
+static struct platform_driver rz_sysc_driver = {
+ .driver = {
+ .name = "renesas-rz-sysc",
+ .suppress_bind_attrs = true,
+ .of_match_table = rz_sysc_match
+ },
+ .probe = rz_sysc_probe
+};
+
+static int __init rz_sysc_init(void)
+{
+ return platform_driver_register(&rz_sysc_driver);
+}
+subsys_initcall(rz_sysc_init);
+
+MODULE_DESCRIPTION("Renesas RZ System Controller Driver");
+MODULE_AUTHOR("Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/renesas/rz-sysc.h b/drivers/soc/renesas/rz-sysc.h
new file mode 100644
index 000000000..921ee0d26
--- /dev/null
+++ b/drivers/soc/renesas/rz-sysc.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Renesas RZ System Controller
+ *
+ * Copyright (C) 2024 Renesas Electronics Corp.
+ */
+
+#ifndef __SOC_RENESAS_RZ_SYSC_H__
+#define __SOC_RENESAS_RZ_SYSC_H__
+
+#include <linux/device.h>
+#include <linux/sys_soc.h>
+#include <linux/types.h>
+
+/**
+ * struct rz_syc_soc_id_init_data - RZ SYSC SoC identification initialization data
+ * @family: RZ SoC family
+ * @id: RZ SoC expected ID
+ * @devid_offset: SYSC SoC ID register offset
+ * @revision_mask: SYSC SoC ID revision mask
+ * @specific_id_mask: SYSC SoC ID specific ID mask
+ * @print_id: print SoC-specific extended device identification
+ */
+struct rz_sysc_soc_id_init_data {
+ const char * const family;
+ u32 id;
+ u32 devid_offset;
+ u32 revision_mask;
+ u32 specific_id_mask;
+ void (*print_id)(struct device *dev, void __iomem *sysc_base,
+ struct soc_device_attribute *soc_dev_attr);
+};
+
+/**
+ * struct rz_sysc_init_data - RZ SYSC initialization data
+ * @soc_id_init_data: RZ SYSC SoC ID initialization data
+ * @writeable_reg: Regmap writeable register check function
+ * @readable_reg: Regmap readable register check function
+ * @max_register: Maximum SYSC register offset to be used by the regmap config
+ */
+struct rz_sysc_init_data {
+ const struct rz_sysc_soc_id_init_data *soc_id_init_data;
+ bool (*writeable_reg)(struct device *dev, unsigned int reg);
+ bool (*readable_reg)(struct device *dev, unsigned int reg);
+ u32 max_register;
+};
+
+extern const struct rz_sysc_init_data rzg3e_sys_init_data;
+extern const struct rz_sysc_init_data rzg3l_sysc_init_data;
+extern const struct rz_sysc_init_data rzg3s_sysc_init_data;
+extern const struct rz_sysc_init_data rzv2h_sys_init_data;
+extern const struct rz_sysc_init_data rzv2n_sys_init_data;
+
+#endif /* __SOC_RENESAS_RZ_SYSC_H__ */
diff --git a/drivers/soc/renesas/rzn1_irqmux.c b/drivers/soc/renesas/rzn1_irqmux.c
new file mode 100644
index 000000000..c3887db7a
--- /dev/null
+++ b/drivers/soc/renesas/rzn1_irqmux.c
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * RZ/N1 GPIO Interrupt Multiplexer
+ *
+ * Copyright 2025 Schneider Electric
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/*
+ * Up to 8 output lines are connected to GIC SPI interrupt controller
+ * starting at IRQ 103.
+ */
+#define RZN1_IRQMUX_GIC_SPI_BASE 103
+#define RZN1_IRQMUX_NUM_OUTPUTS 8
+
+static int rzn1_irqmux_parent_args_to_line_index(struct device *dev,
+ const struct of_phandle_args *parent_args)
+{
+ /*
+ * The parent interrupt should be one of the GIC controller.
+ * Three arguments must be provided.
+ * - args[0]: GIC_SPI
+ * - args[1]: The GIC interrupt number
+ * - args[2]: The interrupt flags
+ *
+ * We retrieve the line index based on the GIC interrupt number
+ * provided.
+ */
+
+ if (parent_args->args_count != 3 || parent_args->args[0] != GIC_SPI) {
+ dev_err(dev, "Invalid interrupt-map item\n");
+ return -EINVAL;
+ }
+
+ if (parent_args->args[1] < RZN1_IRQMUX_GIC_SPI_BASE ||
+ parent_args->args[1] >= RZN1_IRQMUX_GIC_SPI_BASE + RZN1_IRQMUX_NUM_OUTPUTS) {
+ dev_err(dev, "Invalid GIC interrupt %u\n", parent_args->args[1]);
+ return -EINVAL;
+ }
+
+ return parent_args->args[1] - RZN1_IRQMUX_GIC_SPI_BASE;
+}
+
+static int rzn1_irqmux_probe(struct platform_device *pdev)
+{
+ DECLARE_BITMAP(index_done, RZN1_IRQMUX_NUM_OUTPUTS) = {};
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct of_imap_parser imap_parser;
+ struct of_imap_item imap_item;
+ u32 __iomem *regs;
+ int index;
+ int ret;
+ u32 tmp;
+
+ regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ /* We support only #interrupt-cells = <1> and #address-cells = <0> */
+ ret = of_property_read_u32(np, "#interrupt-cells", &tmp);
+ if (ret)
+ return ret;
+ if (tmp != 1)
+ return -EINVAL;
+
+ ret = of_property_read_u32(np, "#address-cells", &tmp);
+ if (ret)
+ return ret;
+ if (tmp != 0)
+ return -EINVAL;
+
+ ret = of_imap_parser_init(&imap_parser, np, &imap_item);
+ if (ret)
+ return ret;
+
+ for_each_of_imap_item(&imap_parser, &imap_item) {
+ index = rzn1_irqmux_parent_args_to_line_index(dev, &imap_item.parent_args);
+ if (index < 0) {
+ of_node_put(imap_item.parent_args.np);
+ return index;
+ }
+
+ if (test_and_set_bit(index, index_done)) {
+ of_node_put(imap_item.parent_args.np);
+ dev_err(dev, "Mux output line %d already defined in interrupt-map\n",
+ index);
+ return -EINVAL;
+ }
+
+ /*
+ * The child #address-cells is 0 (already checked). The first
+ * value in imap item is the src hwirq.
+ */
+ writel(imap_item.child_imap[0], regs + index);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id rzn1_irqmux_of_match[] = {
+ { .compatible = "renesas,rzn1-gpioirqmux", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rzn1_irqmux_of_match);
+
+static struct platform_driver rzn1_irqmux_driver = {
+ .probe = rzn1_irqmux_probe,
+ .driver = {
+ .name = "rzn1_irqmux",
+ .of_match_table = rzn1_irqmux_of_match,
+ },
+};
+module_platform_driver(rzn1_irqmux_driver);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+MODULE_DESCRIPTION("Renesas RZ/N1 GPIO IRQ Multiplexer Driver");
+MODULE_LICENSE("GPL");