public inbox for cip-dev@lists.cip-project.org
 help / color / mirror / Atom feed
* [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support
@ 2026-03-11 11:03 Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 01/28] soc: renesas: Add SYSC driver for Renesas RZ family Claudiu
                   ` (27 more replies)
  0 siblings, 28 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

Hi,

Series adds PCIe support for the Renesas RZ/G3S SoC.
Please have a look.

Thank you,
Claudiu

Amjad Ouled-Ameur (1):
  reset: make shared pulsed reset controls re-triggerable

Claudiu Beznea (16):
  soc: renesas: Add SYSC driver for Renesas RZ family
  soc: renesas: rz-sysc: Move RZ/G3S SoC detection to the SYSC driver
  soc: renesas: rz-sysc: Populate readable_reg/writeable_reg in regmap
    config
  clk: renesas: r9a08g045: Add PCIe clocks and resets
  of/irq: Update the out_irq->np before returning success
  dt-bindings: PCI: Add Renesas RZ/G3S PCIe controller binding
  PCI: Add Renesas RZ/G3S host controller driver
  PCI: rzg3s-host: Initialize MSI status bitmap before use
  PCI: rzg3s-host: Use pci_generic_config_write() for the root bus
  PCI: rzg3s-host: Drop the lock on RZG3S_PCI_MSIRS and
    RZG3S_PCI_PINTRCVIS
  arm64: dts: renesas: r9a08g045: Enable SYS node
  arm64: dts: renesas: r9a08g045: Use syscon compatible for the system
    controller
  arm64: dts: renesas: r9a08g045: Add PCIe node
  arm64: dts: renesas: rzg3s-smarc-som: Add PCIe reference clock
  arm64: dts: renesas: rzg3s-smarc: Enable PCIe
  arm64: defconfig: Enable PCIe for the Renesas RZ/G3S SoC

Felix Gu (1):
  PCI: rzg3s-host: Fix device node reference leak in
    rzg3s_pcie_host_parse_port()

John Madieu (1):
  soc: renesas: rz-sysc: Add syscon/regmap support

Jonathan Cameron (1):
  of: Add cleanup.h based auto release via __free(device_node) markings

Kevin Xie (1):
  PCI: Add PCIE_RESET_CONFIG_DEVICE_WAIT_MS waiting time value

Marc Zyngier (1):
  of/irq: Allow matching of an interrupt-map local to an interrupt
    controller

Marek Vasut (1):
  genirq/msi: Silence 'set affinity failed' warning

Niklas Cassel (2):
  PCI: Rename PCIE_RESET_CONFIG_DEVICE_WAIT_MS to
    PCIE_RESET_CONFIG_WAIT_MS
  PCI: Move link up wait time and max retries macros to pci.h

Peter Griffin (1):
  mfd: syscon: Add of_syscon_register_regmap() API

Philipp Zabel (1):
  reset: Add reset_control_bulk API

Syed Nayyar Waris (1):
  lib/bitmap: add bitmap_{read,write}()

 .../bindings/pci/renesas,r9a08g045-pcie.yaml  |  249 +++
 MAINTAINERS                                   |    8 +
 arch/arm64/boot/dts/renesas/r9a08g045.dtsi    |   68 +-
 .../boot/dts/renesas/rzg3s-smarc-som.dtsi     |    5 +
 arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi  |   11 +
 arch/arm64/configs/defconfig                  |    1 +
 drivers/clk/renesas/r9a08g045-cpg.c           |   19 +
 drivers/mfd/syscon.c                          |   48 +
 drivers/of/irq.c                              |   37 +-
 drivers/pci/controller/Kconfig                |    9 +
 drivers/pci/controller/Makefile               |    1 +
 drivers/pci/controller/pcie-rzg3s-host.c      | 1782 +++++++++++++++++
 drivers/pci/pci.h                             |   19 +
 drivers/reset/core.c                          |  288 +++
 drivers/soc/renesas/Kconfig                   |    9 +
 drivers/soc/renesas/Makefile                  |    2 +
 drivers/soc/renesas/r9a08g045-sysc.c          |   93 +
 drivers/soc/renesas/renesas-soc.c             |    3 -
 drivers/soc/renesas/rz-sysc.c                 |  157 ++
 drivers/soc/renesas/rz-sysc.h                 |   45 +
 include/linux/bitmap.h                        |   77 +
 include/linux/mfd/syscon.h                    |    9 +
 include/linux/msi.h                           |    2 +
 include/linux/of.h                            |    2 +
 include/linux/reset.h                         |  335 ++++
 kernel/irq/msi.c                              |    2 +-
 26 files changed, 3267 insertions(+), 14 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pci/renesas,r9a08g045-pcie.yaml
 create mode 100644 drivers/pci/controller/pcie-rzg3s-host.c
 create mode 100644 drivers/soc/renesas/r9a08g045-sysc.c
 create mode 100644 drivers/soc/renesas/rz-sysc.c
 create mode 100644 drivers/soc/renesas/rz-sysc.h

-- 
2.43.0



^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 01/28] soc: renesas: Add SYSC driver for Renesas RZ family
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 02/28] soc: renesas: rz-sysc: Move RZ/G3S SoC detection to the SYSC driver Claudiu
                   ` (26 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

commit c1aca5588279fc341a2e12d61e853bb1fd4c72d5 upstream.

The RZ/G3S system controller (SYSC) has various registers that control
different functionalities.  One of the exposed register offers
information about the SoC identification.

Add a driver that identifies the SoC.  Later the driver will be extended
with other functionalities.

Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Signed-off-by: John Madieu <john.madieu.xa@bp.renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Link: https://lore.kernel.org/20250128031342.52675-2-john.madieu.xa@bp.renesas.com
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
[claudiu.beznea:
 - fixed conflict in Makefile and Kconfig by keeping the
   code from v5.10 CIP and from this patch
 - include linux/module.h to avoid compilation errors]
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 drivers/soc/renesas/Kconfig   |   3 +
 drivers/soc/renesas/Makefile  |   1 +
 drivers/soc/renesas/rz-sysc.c | 124 ++++++++++++++++++++++++++++++++++
 drivers/soc/renesas/rz-sysc.h |  37 ++++++++++
 4 files changed, 165 insertions(+)
 create mode 100644 drivers/soc/renesas/rz-sysc.c
 create mode 100644 drivers/soc/renesas/rz-sysc.h

diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig
index f9aed9eb9f43..f5dc9e425dff 100644
--- a/drivers/soc/renesas/Kconfig
+++ b/drivers/soc/renesas/Kconfig
@@ -430,4 +430,7 @@ config SYSC_R8A774B1
 	bool "System Controller support for RZ/G2N" if COMPILE_TEST
 	select SYSC_RCAR
 
+config SYSC_RZ
+	bool "System controller for RZ SoCs" if COMPILE_TEST
+
 endif # SOC_RENESAS
diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile
index c571e8ef9192..4a84f1945b3f 100644
--- a/drivers/soc/renesas/Makefile
+++ b/drivers/soc/renesas/Makefile
@@ -34,3 +34,4 @@ obj-$(CONFIG_PWC_RZV2M)		+= pwc-rzv2m.o
 obj-$(CONFIG_RST_RCAR)		+= rcar-rst.o
 obj-$(CONFIG_SYSC_RCAR)		+= rcar-sysc.o
 obj-$(CONFIG_SYSC_RMOBILE)	+= rmobile-sysc.o
+obj-$(CONFIG_SYSC_RZ)		+= rz-sysc.o
diff --git a/drivers/soc/renesas/rz-sysc.c b/drivers/soc/renesas/rz-sysc.c
new file mode 100644
index 000000000000..e00ec20298db
--- /dev/null
+++ b/drivers/soc/renesas/rz-sysc.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ System controller driver
+ *
+ * Copyright (C) 2024 Renesas Electronics Corp.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/sys_soc.h>
+
+#include "rz-sysc.h"
+
+#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1))
+
+/**
+ * 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;
+	}
+
+	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[] = {
+	{ }
+};
+MODULE_DEVICE_TABLE(of, rz_sysc_match);
+
+static int rz_sysc_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *match;
+	struct device *dev = &pdev->dev;
+	struct rz_sysc *sysc;
+
+	match = of_match_node(rz_sysc_match, dev->of_node);
+	if (!match)
+		return -ENODEV;
+
+	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;
+	return rz_sysc_soc_init(sysc, match);
+}
+
+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 000000000000..c9ef7e83de59
--- /dev/null
+++ b/drivers/soc/renesas/rz-sysc.h
@@ -0,0 +1,37 @@
+/* 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/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
+ */
+struct rz_sysc_soc_id_init_data {
+	const char * const family;
+	u32 id;
+	u32 devid_offset;
+	u32 revision_mask;
+	u32 specific_id_mask;
+};
+
+/**
+ * struct rz_sysc_init_data - RZ SYSC initialization data
+ * @soc_id_init_data: RZ SYSC SoC ID initialization data
+ */
+struct rz_sysc_init_data {
+	const struct rz_sysc_soc_id_init_data *soc_id_init_data;
+};
+
+#endif /* __SOC_RENESAS_RZ_SYSC_H__ */
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 02/28] soc: renesas: rz-sysc: Move RZ/G3S SoC detection to the SYSC driver
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 01/28] soc: renesas: Add SYSC driver for Renesas RZ family Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 03/28] mfd: syscon: Add of_syscon_register_regmap() API Claudiu
                   ` (25 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

commit 0704de89eee60e2f968973c7b4ccd8cd219b2d97 upstream.

Now that we have SoC detection in the RZ SYSC driver, move the RZ/G3S
SoC detection to it. The SYSC provides SoC ID in its own registers.

Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: John Madieu <john.madieu.xa@bp.renesas.com>
Link: https://lore.kernel.org/20250128031342.52675-3-john.madieu.xa@bp.renesas.com
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
[claudiu.beznea: fixed conflict in renesas-soc.c by dropping the RZ/V2H
 code as this is not present in v5.10 CIP]
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 drivers/soc/renesas/Kconfig          |  5 +++++
 drivers/soc/renesas/Makefile         |  1 +
 drivers/soc/renesas/r9a08g045-sysc.c | 23 +++++++++++++++++++++++
 drivers/soc/renesas/renesas-soc.c    |  3 ---
 drivers/soc/renesas/rz-sysc.c        |  3 +++
 drivers/soc/renesas/rz-sysc.h        |  2 ++
 6 files changed, 34 insertions(+), 3 deletions(-)
 create mode 100644 drivers/soc/renesas/r9a08g045-sysc.c

diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig
index f5dc9e425dff..be8cdebce46d 100644
--- a/drivers/soc/renesas/Kconfig
+++ b/drivers/soc/renesas/Kconfig
@@ -306,6 +306,7 @@ config ARCH_R9A07G054
 config ARCH_R9A08G045
 	bool "ARM64 Platform support for RZ/G3S"
 	select ARCH_RZG2L
+	select SYSC_R9A08G045
 	help
 	  This enables support for the Renesas RZ/G3S SoC variants.
 
@@ -433,4 +434,8 @@ config SYSC_R8A774B1
 config SYSC_RZ
 	bool "System controller for RZ SoCs" if COMPILE_TEST
 
+config SYSC_R9A08G045
+	bool "Renesas RZ/G3S System controller support" if COMPILE_TEST
+	select SYSC_RZ
+
 endif # SOC_RENESAS
diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile
index 4a84f1945b3f..1013a7a18afb 100644
--- a/drivers/soc/renesas/Makefile
+++ b/drivers/soc/renesas/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_SYSC_R8A779A0)	+= r8a779a0-sysc.o
 ifdef CONFIG_SMP
 obj-$(CONFIG_ARCH_R9A06G032)	+= r9a06g032-smp.o
 endif
+obj-$(CONFIG_SYSC_R9A08G045)	+= r9a08g045-sysc.o
 
 # Family
 obj-$(CONFIG_PWC_RZV2M)		+= pwc-rzv2m.o
diff --git a/drivers/soc/renesas/r9a08g045-sysc.c b/drivers/soc/renesas/r9a08g045-sysc.c
new file mode 100644
index 000000000000..f4db1431e036
--- /dev/null
+++ b/drivers/soc/renesas/r9a08g045-sysc.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/G3S System controller driver
+ *
+ * Copyright (C) 2024 Renesas Electronics Corp.
+ */
+
+#include <linux/bits.h>
+#include <linux/init.h>
+
+#include "rz-sysc.h"
+
+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),
+};
+
+const struct rz_sysc_init_data rzg3s_sysc_init_data __initconst = {
+	.soc_id_init_data = &rzg3s_sysc_soc_id_init_data,
+};
diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c
index 854020afd1ab..ffdc8625a63f 100644
--- a/drivers/soc/renesas/renesas-soc.c
+++ b/drivers/soc/renesas/renesas-soc.c
@@ -365,9 +365,6 @@ static const struct of_device_id renesas_socs[] __initconst = {
 #ifdef CONFIG_ARCH_R9A07G054
 	{ .compatible = "renesas,r9a07g054",	.data = &soc_rz_v2l },
 #endif
-#ifdef CONFIG_ARCH_R9A08G045
-	{ .compatible = "renesas,r9a08g045",	.data = &soc_rz_g3s },
-#endif
 #ifdef CONFIG_ARCH_R9A09G011
 	{ .compatible = "renesas,r9a09g011",	.data = &soc_rz_v2m },
 #endif
diff --git a/drivers/soc/renesas/rz-sysc.c b/drivers/soc/renesas/rz-sysc.c
index e00ec20298db..d716542a7a4a 100644
--- a/drivers/soc/renesas/rz-sysc.c
+++ b/drivers/soc/renesas/rz-sysc.c
@@ -78,6 +78,9 @@ static int rz_sysc_soc_init(struct rz_sysc *sysc, const struct of_device_id *mat
 }
 
 static const struct of_device_id rz_sysc_match[] = {
+#ifdef CONFIG_SYSC_R9A08G045
+	{ .compatible = "renesas,r9a08g045-sysc", .data = &rzg3s_sysc_init_data },
+#endif
 	{ }
 };
 MODULE_DEVICE_TABLE(of, rz_sysc_match);
diff --git a/drivers/soc/renesas/rz-sysc.h b/drivers/soc/renesas/rz-sysc.h
index c9ef7e83de59..908f09fa4fc9 100644
--- a/drivers/soc/renesas/rz-sysc.h
+++ b/drivers/soc/renesas/rz-sysc.h
@@ -34,4 +34,6 @@ struct rz_sysc_init_data {
 	const struct rz_sysc_soc_id_init_data *soc_id_init_data;
 };
 
+extern const struct rz_sysc_init_data rzg3s_sysc_init_data;
+
 #endif /* __SOC_RENESAS_RZ_SYSC_H__ */
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 03/28] mfd: syscon: Add of_syscon_register_regmap() API
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 01/28] soc: renesas: Add SYSC driver for Renesas RZ family Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 02/28] soc: renesas: rz-sysc: Move RZ/G3S SoC detection to the SYSC driver Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 04/28] soc: renesas: rz-sysc: Add syscon/regmap support Claudiu
                   ` (24 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Peter Griffin <peter.griffin@linaro.org>

commit 769cb63166d90f1fadafa4352f180cbd96b6cb77 upstream.

The of_syscon_register_regmap() API allows an externally created regmap
to be registered with syscon. This regmap can then be returned to client
drivers using the syscon_regmap_lookup_by_phandle() APIs.

The API is used by platforms where mmio access to the syscon registers is
not possible, and a underlying soc driver like exynos-pmu provides a SoC
specific regmap that can issue a SMC or hypervisor call to write the
register.

This approach keeps the SoC complexities out of syscon, but allows common
drivers such as  syscon-poweroff, syscon-reboot and friends that are used
by many SoCs already to be re-used.

Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Sam Protsenko <semen.protsenko@linaro.org>
Tested-by: Will McVicker <willmcvicker@google.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Link: https://lore.kernel.org/r/20240621115544.1655458-2-peter.griffin@linaro.org
Signed-off-by: Lee Jones <lee@kernel.org>
[claudiu.beznea: fixed conflict in syscon.h by keeping the previous
 definitions for the conflicting lines and the newly introduced one from
 this patch]
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 drivers/mfd/syscon.c       | 48 ++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/syscon.h |  9 +++++++
 2 files changed, 57 insertions(+)

diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
index 4d536a097e8c..381a71a57d0e 100644
--- a/drivers/mfd/syscon.c
+++ b/drivers/mfd/syscon.c
@@ -178,6 +178,54 @@ static struct regmap *device_node_get_regmap(struct device_node *np,
 	return syscon->regmap;
 }
 
+/**
+ * of_syscon_register_regmap() - Register regmap for specified device node
+ * @np: Device tree node
+ * @regmap: Pointer to regmap object
+ *
+ * Register an externally created regmap object with syscon for the specified
+ * device tree node. This regmap will then be returned to client drivers using
+ * the syscon_regmap_lookup_by_phandle() API.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int of_syscon_register_regmap(struct device_node *np, struct regmap *regmap)
+{
+	struct syscon *entry, *syscon = NULL;
+	int ret;
+
+	if (!np || !regmap)
+		return -EINVAL;
+
+	syscon = kzalloc(sizeof(*syscon), GFP_KERNEL);
+	if (!syscon)
+		return -ENOMEM;
+
+	/* check if syscon entry already exists */
+	spin_lock(&syscon_list_slock);
+
+	list_for_each_entry(entry, &syscon_list, list)
+		if (entry->np == np) {
+			ret = -EEXIST;
+			goto err_unlock;
+		}
+
+	syscon->regmap = regmap;
+	syscon->np = np;
+
+	/* register the regmap in syscon list */
+	list_add_tail(&syscon->list, &syscon_list);
+	spin_unlock(&syscon_list_slock);
+
+	return 0;
+
+err_unlock:
+	spin_unlock(&syscon_list_slock);
+	kfree(syscon);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(of_syscon_register_regmap);
+
 struct regmap *device_node_to_regmap(struct device_node *np)
 {
 	return device_node_get_regmap(np, false);
diff --git a/include/linux/mfd/syscon.h b/include/linux/mfd/syscon.h
index 7f20e9b502a5..dd5f972ffcdf 100644
--- a/include/linux/mfd/syscon.h
+++ b/include/linux/mfd/syscon.h
@@ -28,6 +28,8 @@ extern struct regmap *syscon_regmap_lookup_by_phandle_args(
 					const char *property,
 					int arg_count,
 					unsigned int *out_args);
+int of_syscon_register_regmap(struct device_node *np,
+			      struct regmap *regmap);
 #else
 static inline struct regmap *device_node_to_regmap(struct device_node *np)
 {
@@ -59,6 +61,13 @@ static inline struct regmap *syscon_regmap_lookup_by_phandle_args(
 {
 	return ERR_PTR(-ENOTSUPP);
 }
+
+static inline int of_syscon_register_regmap(struct device_node *np,
+					struct regmap *regmap)
+{
+	return -EOPNOTSUPP;
+}
+
 #endif
 
 #endif /* __LINUX_MFD_SYSCON_H__ */
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 04/28] soc: renesas: rz-sysc: Add syscon/regmap support
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (2 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 03/28] mfd: syscon: Add of_syscon_register_regmap() API Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 05/28] soc: renesas: rz-sysc: Populate readable_reg/writeable_reg in regmap config Claudiu
                   ` (23 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: John Madieu <john.madieu.xa@bp.renesas.com>

commit 2da2740fb9c8e26b6b5e20d74f2ed1d49824236d upstream.

The RZ/G3E system controller has various registers that control or report
some properties specific to individual IPs. The regmap is registered as a
syscon device to allow these IP drivers to access the registers through the
regmap API.

As other RZ SoCs might have custom read/write callbacks or max-offsets,
register a custom regmap configuration.

Signed-off-by: John Madieu <john.madieu.xa@bp.renesas.com>
[claudiu.beznea:
 - do not check the match->data validity in rz_sysc_probe() as it is
   always valid
 - dinamically allocate regmap_cfg]
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> # on RZ/G3S
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Link: https://lore.kernel.org/20250818162859.9661-2-john.madieu.xa@bp.renesas.com
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
[claudiu.beznea:
 - drop references to RZ/V2H (r9a09g057-sys.c) and RZ/G3E
   (r9a09g047-sys.c) as these are not present in v5.10 CIP
 - fixed conflict in the include section of rz-sysc.c by keeping both
   conflicting lines alphanumerically sorted]
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 drivers/soc/renesas/Kconfig          |  1 +
 drivers/soc/renesas/r9a08g045-sysc.c |  1 +
 drivers/soc/renesas/rz-sysc.c        | 30 +++++++++++++++++++++++++++-
 drivers/soc/renesas/rz-sysc.h        |  2 ++
 4 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig
index be8cdebce46d..407c76d952b9 100644
--- a/drivers/soc/renesas/Kconfig
+++ b/drivers/soc/renesas/Kconfig
@@ -433,6 +433,7 @@ config SYSC_R8A774B1
 
 config SYSC_RZ
 	bool "System controller for RZ SoCs" if COMPILE_TEST
+	select MFD_SYSCON
 
 config SYSC_R9A08G045
 	bool "Renesas RZ/G3S System controller support" if COMPILE_TEST
diff --git a/drivers/soc/renesas/r9a08g045-sysc.c b/drivers/soc/renesas/r9a08g045-sysc.c
index f4db1431e036..0504d4e68761 100644
--- a/drivers/soc/renesas/r9a08g045-sysc.c
+++ b/drivers/soc/renesas/r9a08g045-sysc.c
@@ -20,4 +20,5 @@ static const struct rz_sysc_soc_id_init_data rzg3s_sysc_soc_id_init_data __initc
 
 const struct rz_sysc_init_data rzg3s_sysc_init_data __initconst = {
 	.soc_id_init_data = &rzg3s_sysc_soc_id_init_data,
+	.max_register = 0xe20,
 };
diff --git a/drivers/soc/renesas/rz-sysc.c b/drivers/soc/renesas/rz-sysc.c
index d716542a7a4a..115961483845 100644
--- a/drivers/soc/renesas/rz-sysc.c
+++ b/drivers/soc/renesas/rz-sysc.c
@@ -5,10 +5,14 @@
  * Copyright (C) 2024 Renesas Electronics Corp.
  */
 
+#include <linux/cleanup.h>
 #include <linux/io.h>
+#include <linux/mfd/syscon.h>
 #include <linux/module.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"
@@ -87,14 +91,23 @@ 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(sizeof(*regmap_cfg), GFP_KERNEL);
+	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;
@@ -104,7 +117,22 @@ static int rz_sysc_probe(struct platform_device *pdev)
 		return PTR_ERR(sysc->base);
 
 	sysc->dev = dev;
-	return rz_sysc_soc_init(sysc, match);
+	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 = 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 = {
diff --git a/drivers/soc/renesas/rz-sysc.h b/drivers/soc/renesas/rz-sysc.h
index 908f09fa4fc9..8a3507989c04 100644
--- a/drivers/soc/renesas/rz-sysc.h
+++ b/drivers/soc/renesas/rz-sysc.h
@@ -29,9 +29,11 @@ struct rz_sysc_soc_id_init_data {
 /**
  * struct rz_sysc_init_data - RZ SYSC initialization data
  * @soc_id_init_data: RZ SYSC SoC ID initialization data
+ * @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;
+	u32 max_register;
 };
 
 extern const struct rz_sysc_init_data rzg3s_sysc_init_data;
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 05/28] soc: renesas: rz-sysc: Populate readable_reg/writeable_reg in regmap config
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (3 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 04/28] soc: renesas: rz-sysc: Add syscon/regmap support Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-24  9:26   ` Pavel Machek
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 06/28] clk: renesas: r9a08g045: Add PCIe clocks and resets Claudiu
                   ` (22 subsequent siblings)
  27 siblings, 1 reply; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

commit c432180a7d95081353a96fd6d5bd75b0fc8a27c3 upstream.

Not all system controller registers are accessible from Linux. Accessing
such registers generates synchronous external abort. Populate the
readable_reg and writeable_reg members of the regmap config to inform the
regmap core which registers can be accessed. The list will need to be
updated whenever new system controller functionality is exported through
regmap.

Fixes: 2da2740fb9c8 ("soc: renesas: rz-sysc: Add syscon/regmap support")
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Link: https://patch.msgid.link/20251105070526.264445-3-claudiu.beznea.uj@bp.renesas.com
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
[claudiu.beznea: dropped sysc file for:
 - RZ/G3E (drivers/soc/renesas/r9a09g047-sys.c)
 - RZ/V2N (drivers/soc/renesas/r9a09g056-sys.c)
 - RZ/V2H (drivers/soc/renesas/r9a09g057-sys.c)
 as these are not present in v5.10 CIP]
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 drivers/soc/renesas/r9a08g045-sysc.c | 69 ++++++++++++++++++++++++++++
 drivers/soc/renesas/rz-sysc.c        |  2 +
 drivers/soc/renesas/rz-sysc.h        |  4 ++
 3 files changed, 75 insertions(+)

diff --git a/drivers/soc/renesas/r9a08g045-sysc.c b/drivers/soc/renesas/r9a08g045-sysc.c
index 0504d4e68761..03d653d5cde5 100644
--- a/drivers/soc/renesas/r9a08g045-sysc.c
+++ b/drivers/soc/renesas/r9a08g045-sysc.c
@@ -6,10 +6,29 @@
  */
 
 #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,
@@ -18,7 +37,57 @@ static const struct rz_sysc_soc_id_init_data rzg3s_sysc_soc_id_init_data __initc
 	.specific_id_mask = GENMASK(27, 0),
 };
 
+static bool rzg3s_regmap_readable_reg(struct device *dev, 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_GETH0_CFG:
+	case SYS_GETH1_CFG:
+	case SYS_PCIE_CFG:
+	case SYS_PCIE_MON:
+	case SYS_PCIE_ERR_MON:
+	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_writeable_reg(struct device *dev, 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;
+	}
+}
+
 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/rz-sysc.c b/drivers/soc/renesas/rz-sysc.c
index 115961483845..805994c9710e 100644
--- a/drivers/soc/renesas/rz-sysc.c
+++ b/drivers/soc/renesas/rz-sysc.c
@@ -127,6 +127,8 @@ static int rz_sysc_probe(struct platform_device *pdev)
 	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))
diff --git a/drivers/soc/renesas/rz-sysc.h b/drivers/soc/renesas/rz-sysc.h
index 8a3507989c04..5b85b6431a47 100644
--- a/drivers/soc/renesas/rz-sysc.h
+++ b/drivers/soc/renesas/rz-sysc.h
@@ -29,10 +29,14 @@ struct rz_sysc_soc_id_init_data {
 /**
  * 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;
 };
 
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 06/28] clk: renesas: r9a08g045: Add PCIe clocks and resets
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (4 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 05/28] soc: renesas: rz-sysc: Populate readable_reg/writeable_reg in regmap config Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 07/28] lib/bitmap: add bitmap_{read,write}() Claudiu
                   ` (21 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

commit 6b234eda88d781d244094836afc37c90b57832f3 upstream.

Add clocks and resets for the PCIe IP available on the Renesas RZ/G3S
SoC.  The clkl1pm clock is required for PCIe link power management (PM)
control and should be enabled based on the state of the CLKREQ# pin.
Therefore, mark it as a no_pm clock to allow the PCIe driver to manage
it during link PM transitions.

Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Link: https://lore.kernel.org/20250704161410.3931884-3-claudiu.beznea.uj@bp.renesas.com
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
[claudiu.beznea: fixed conflict by dropping I3C clocks and resets as
 these are not yet present in v5.10 CIP]
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 drivers/clk/renesas/r9a08g045-cpg.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/drivers/clk/renesas/r9a08g045-cpg.c b/drivers/clk/renesas/r9a08g045-cpg.c
index c3b64f94e188..3e8eae79af09 100644
--- a/drivers/clk/renesas/r9a08g045-cpg.c
+++ b/drivers/clk/renesas/r9a08g045-cpg.c
@@ -283,6 +283,10 @@ static const struct rzg2l_mod_clk r9a08g045_mod_clks[] = {
 					MSTOP(BUS_MCPU2, BIT(14))),
 	DEF_MOD("tsu_pclk",		R9A08G045_TSU_PCLK, R9A08G045_CLK_TSU, 0x5ac, 0,
 					MSTOP(BUS_MCPU2, BIT(15))),
+	DEF_MOD("pci_aclk",		R9A08G045_PCI_ACLK, R9A08G045_CLK_M0, 0x608, 0,
+					MSTOP(BUS_PERI_COM, BIT(10))),
+	DEF_MOD("pci_clkl1pm",		R9A08G045_PCI_CLKL1PM, R9A08G045_CLK_ZT, 0x608, 1,
+					MSTOP(BUS_PERI_COM, BIT(10))),
 	DEF_MOD("vbat_bclk",		R9A08G045_VBAT_BCLK, R9A08G045_OSCCLK, 0x614, 0,
 					MSTOP(BUS_MCPU3, GENMASK(8, 7))),
 };
@@ -319,6 +323,13 @@ static const struct rzg2l_reset r9a08g045_resets[] = {
 	DEF_RST(R9A08G045_ADC_PRESETN, 0x8a8, 0),
 	DEF_RST(R9A08G045_ADC_ADRST_N, 0x8a8, 1),
 	DEF_RST(R9A08G045_TSU_PRESETN, 0x8ac, 0),
+	DEF_RST(R9A08G045_PCI_ARESETN, 0x908, 0),
+	DEF_RST(R9A08G045_PCI_RST_B, 0x908, 1),
+	DEF_RST(R9A08G045_PCI_RST_GP_B, 0x908, 2),
+	DEF_RST(R9A08G045_PCI_RST_PS_B, 0x908, 3),
+	DEF_RST(R9A08G045_PCI_RST_RSM_B, 0x908, 4),
+	DEF_RST(R9A08G045_PCI_RST_CFG_B, 0x908, 5),
+	DEF_RST(R9A08G045_PCI_RST_LOAD_B, 0x908, 6),
 	DEF_RST(R9A08G045_VBAT_BRESETN, 0x914, 0),
 };
 
@@ -330,6 +341,10 @@ static const unsigned int r9a08g045_crit_mod_clks[] __initconst = {
 	MOD_CLK_BASE + R9A08G045_VBAT_BCLK,
 };
 
+static const unsigned int r9a08g045_no_pm_mod_clks[] = {
+	MOD_CLK_BASE + R9A08G045_PCI_CLKL1PM,
+};
+
 const struct rzg2l_cpg_info r9a08g045_cpg_info = {
 	/* Core Clocks */
 	.core_clks = r9a08g045_core_clks,
@@ -346,6 +361,10 @@ const struct rzg2l_cpg_info r9a08g045_cpg_info = {
 	.num_mod_clks = ARRAY_SIZE(r9a08g045_mod_clks),
 	.num_hw_mod_clks = R9A08G045_VBAT_BCLK + 1,
 
+	/* No PM modules Clocks */
+	.no_pm_mod_clks = r9a08g045_no_pm_mod_clks,
+	.num_no_pm_mod_clks = ARRAY_SIZE(r9a08g045_no_pm_mod_clks),
+
 	/* Resets */
 	.resets = r9a08g045_resets,
 	.num_resets = R9A08G045_VBAT_BRESETN + 1, /* Last reset ID + 1 */
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 07/28] lib/bitmap: add bitmap_{read,write}()
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (5 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 06/28] clk: renesas: r9a08g045: Add PCIe clocks and resets Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-24  9:29   ` Pavel Machek
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 08/28] genirq/msi: Silence 'set affinity failed' warning Claudiu
                   ` (20 subsequent siblings)
  27 siblings, 1 reply; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Syed Nayyar Waris <syednwaris@gmail.com>

commit 63c15822b8dd02a2423cfd92232245ace3f7a11b upstream.

The two new functions allow reading/writing values of length up to
BITS_PER_LONG bits at arbitrary position in the bitmap.

The code was taken from "bitops: Introduce the for_each_set_clump macro"
by Syed Nayyar Waris with a number of changes and simplifications:
 - instead of using roundup(), which adds an unnecessary dependency
   on <linux/math.h>, we calculate space as BITS_PER_LONG-offset;
 - indentation is reduced by not using else-clauses (suggested by
   checkpatch for bitmap_get_value());
 - bitmap_get_value()/bitmap_set_value() are renamed to bitmap_read()
   and bitmap_write();
 - some redundant computations are omitted.

Cc: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Syed Nayyar Waris <syednwaris@gmail.com>
Signed-off-by: William Breathitt Gray <william.gray@linaro.org>
Link: https://lore.kernel.org/lkml/fe12eedf3666f4af5138de0e70b67a07c7f40338.1592224129.git.syednwaris@gmail.com/
Suggested-by: Yury Norov <yury.norov@gmail.com>
Co-developed-by: Alexander Potapenko <glider@google.com>
Signed-off-by: Alexander Potapenko <glider@google.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Yury Norov <yury.norov@gmail.com>
Signed-off-by: Yury Norov <yury.norov@gmail.com>
Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 include/linux/bitmap.h | 77 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
index 29b19d2ba5ba..22e3269342f7 100644
--- a/include/linux/bitmap.h
+++ b/include/linux/bitmap.h
@@ -78,6 +78,10 @@ struct device;
  *  bitmap_to_arr32(buf, src, nbits)            Copy nbits from buf to u32[] dst
  *  bitmap_get_value8(map, start)               Get 8bit value from map at start
  *  bitmap_set_value8(map, value, start)        Set 8bit value to map at start
+ *  bitmap_read(map, start, nbits)              Read an nbits-sized value from
+ *                                              map at start
+ *  bitmap_write(map, value, start, nbits)      Write an nbits-sized value to
+ *                                              map at start
  *
  * Note, bitmap_zero() and bitmap_fill() operate over the region of
  * unsigned longs, that is, bits behind bitmap till the unsigned long
@@ -601,6 +605,79 @@ static inline void bitmap_set_value8(unsigned long *map, unsigned long value,
 	map[index] |= value << offset;
 }
 
+/**
+ * bitmap_read - read a value of n-bits from the memory region
+ * @map: address to the bitmap memory region
+ * @start: bit offset of the n-bit value
+ * @nbits: size of value in bits, nonzero, up to BITS_PER_LONG
+ *
+ * Returns: value of @nbits bits located at the @start bit offset within the
+ * @map memory region. For @nbits = 0 and @nbits > BITS_PER_LONG the return
+ * value is undefined.
+ */
+static inline unsigned long bitmap_read(const unsigned long *map,
+					unsigned long start,
+					unsigned long nbits)
+{
+	size_t index = BIT_WORD(start);
+	unsigned long offset = start % BITS_PER_LONG;
+	unsigned long space = BITS_PER_LONG - offset;
+	unsigned long value_low, value_high;
+
+	if (unlikely(!nbits || nbits > BITS_PER_LONG))
+		return 0;
+
+	if (space >= nbits)
+		return (map[index] >> offset) & BITMAP_LAST_WORD_MASK(nbits);
+
+	value_low = map[index] & BITMAP_FIRST_WORD_MASK(start);
+	value_high = map[index + 1] & BITMAP_LAST_WORD_MASK(start + nbits);
+	return (value_low >> offset) | (value_high << space);
+}
+
+/**
+ * bitmap_write - write n-bit value within a memory region
+ * @map: address to the bitmap memory region
+ * @value: value to write, clamped to nbits
+ * @start: bit offset of the n-bit value
+ * @nbits: size of value in bits, nonzero, up to BITS_PER_LONG.
+ *
+ * bitmap_write() behaves as-if implemented as @nbits calls of __assign_bit(),
+ * i.e. bits beyond @nbits are ignored:
+ *
+ *   for (bit = 0; bit < nbits; bit++)
+ *           __assign_bit(start + bit, bitmap, val & BIT(bit));
+ *
+ * For @nbits == 0 and @nbits > BITS_PER_LONG no writes are performed.
+ */
+static inline void bitmap_write(unsigned long *map, unsigned long value,
+				unsigned long start, unsigned long nbits)
+{
+	size_t index;
+	unsigned long offset;
+	unsigned long space;
+	unsigned long mask;
+	bool fit;
+
+	if (unlikely(!nbits || nbits > BITS_PER_LONG))
+		return;
+
+	mask = BITMAP_LAST_WORD_MASK(nbits);
+	value &= mask;
+	offset = start % BITS_PER_LONG;
+	space = BITS_PER_LONG - offset;
+	fit = space >= nbits;
+	index = BIT_WORD(start);
+
+	map[index] &= (fit ? (~(mask << offset)) : ~BITMAP_FIRST_WORD_MASK(start));
+	map[index] |= value << offset;
+	if (fit)
+		return;
+
+	map[index + 1] &= BITMAP_FIRST_WORD_MASK(start + nbits);
+	map[index + 1] |= (value >> space);
+}
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __LINUX_BITMAP_H */
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 08/28] genirq/msi: Silence 'set affinity failed' warning
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (6 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 07/28] lib/bitmap: add bitmap_{read,write}() Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 09/28] PCI: Add PCIE_RESET_CONFIG_DEVICE_WAIT_MS waiting time value Claudiu
                   ` (19 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Marek Vasut <marek.vasut+renesas@mailbox.org>

commit 5297bba507dc54045e6efeb9955c1271ca9aafe1 upstream.

Various PCI controllers that mux MSIs onto a single IRQ line produce these
"IRQ%d: set affinity failed" warnings when entering suspend. This has been
discussed before [1] [2] and an example test case is included at the end of
this commit message.

Controller drivers that create MSI IRQ domain with
MSI_FLAG_USE_DEF_CHIP_OPS and do not override the .irq_set_affinity()
irqchip callback get assigned the default msi_domain_set_affinity()
callback. That is not desired on controllers where it is not possible to
set affinity of each MSI IRQ line to a specific CPU core due to hardware
limitation.

Introduce flag MSI_FLAG_NO_AFFINITY, which keeps .irq_set_affinity() unset
if the controller driver did not assign it.  This way, migrate_one_irq()
can exit right away, without printing the warning. The .irq_set_affinity()
implementations which only return -EINVAL can be removed from multiple
controller drivers.

  $ grep 25 /proc/interrupts
   25:   0 0 0 0 0 0 0 0   PCIe MSI   0   Edge   PCIe PME

  $ echo core > /sys/power/pm_test ; echo mem > /sys/power/state
  ...
  Disabling non-boot CPUs ...
  IRQ25: set affinity failed(-22). <---------- This is being silenced here
  psci: CPU7 killed (polled 4 ms)
  ...

[1] https://lore.kernel.org/all/d4a6eea3c5e33a3a4056885419df95a7@kernel.org/
[2] https://lore.kernel.org/all/5f4947b18bf381615a37aa81c2242477@kernel.org/

Link: https://lore.kernel.org/r/20240723132958.41320-2-marek.vasut+renesas@mailbox.org
Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
[bhelgaas: commit log]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
[claudiu.beznea: fixed conflict in msi.h by keeping the 5.10 CIP
 definitions for MSI_FLAG_LEVEL_CAPABLE along with the MSI_FLAG_NO_AFFINITY
 introduced by this commit]
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 include/linux/msi.h | 2 ++
 kernel/irq/msi.c    | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/include/linux/msi.h b/include/linux/msi.h
index 70c910b23e13..5eb708a3bcc1 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -370,6 +370,8 @@ enum {
 	MSI_FLAG_MUST_REACTIVATE	= (1 << 5),
 	/* Is level-triggered capable, using two messages */
 	MSI_FLAG_LEVEL_CAPABLE		= (1 << 6),
+	/* PCI MSIs cannot be steered separately to CPU cores */
+	MSI_FLAG_NO_AFFINITY		= (1 << 21),
 };
 
 int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
index 4457f3e966d0..2bde5ce72d70 100644
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -272,7 +272,7 @@ static void msi_domain_update_chip_ops(struct msi_domain_info *info)
 	struct irq_chip *chip = info->chip;
 
 	BUG_ON(!chip || !chip->irq_mask || !chip->irq_unmask);
-	if (!chip->irq_set_affinity)
+	if (!chip->irq_set_affinity && !(info->flags & MSI_FLAG_NO_AFFINITY))
 		chip->irq_set_affinity = msi_domain_set_affinity;
 }
 
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 09/28] PCI: Add PCIE_RESET_CONFIG_DEVICE_WAIT_MS waiting time value
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (7 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 08/28] genirq/msi: Silence 'set affinity failed' warning Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-24  9:33   ` Pavel Machek
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 10/28] PCI: Rename PCIE_RESET_CONFIG_DEVICE_WAIT_MS to PCIE_RESET_CONFIG_WAIT_MS Claudiu
                   ` (18 subsequent siblings)
  27 siblings, 1 reply; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Kevin Xie <kevin.xie@starfivetech.com>

commit d5ceb9496c565eb5763c127c6eb2d2b3068ab1df upstream.

Add the PCIE_RESET_CONFIG_DEVICE_WAIT_MS macro to define the minimum
waiting time between exit from a conventional reset and sending the
first configuration request to the device.

As described in PCIe r6.0, sec 6.6.1 <Conventional Reset>, there are two
different use cases of the value:

   - "With a Downstream Port that does not support Link speeds greater
     than 5.0 GT/s, software must wait a minimum of 100 ms following exit
     from a Conventional Reset before sending a Configuration Request to
     the device immediately below that Port."

   - "With a Downstream Port that supports Link speeds greater than
     5.0 GT/s, software must wait a minimum of 100 ms after Link training
     completes before sending a Configuration Request to the device
     immediately below that Port."

[kwilczynski: commit log]
Link: https://lore.kernel.org/linux-pci/20240328091835.14797-21-minda.chen@starfivetech.com
Signed-off-by: Kevin Xie <kevin.xie@starfivetech.com>
Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Mason Huo <mason.huo@starfivetech.com>
[claudiu.beznea: fixed conflict by keeping only the definition for
 PCIE_RESET_CONFIG_DEVICE_WAIT_MS]
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 drivers/pci/pci.h | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index c2fd92a9ee1a..a391e4db9401 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -11,6 +11,21 @@
 
 #define PCI_VSEC_ID_INTEL_TBT	0x1234	/* Thunderbolt */
 
+/*
+ * PCIe r6.0, sec 6.6.1 <Conventional Reset>
+ *
+ * - "With a Downstream Port that does not support Link speeds greater
+ *    than 5.0 GT/s, software must wait a minimum of 100 ms following exit
+ *    from a Conventional Reset before sending a Configuration Request to
+ *    the device immediately below that Port."
+ *
+ * - "With a Downstream Port that supports Link speeds greater than
+ *    5.0 GT/s, software must wait a minimum of 100 ms after Link training
+ *    completes before sending a Configuration Request to the device
+ *    immediately below that Port."
+ */
+#define PCIE_RESET_CONFIG_DEVICE_WAIT_MS	100
+
 extern const unsigned char pcie_link_speed[];
 extern bool pci_early_dump;
 
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 10/28] PCI: Rename PCIE_RESET_CONFIG_DEVICE_WAIT_MS to PCIE_RESET_CONFIG_WAIT_MS
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (8 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 09/28] PCI: Add PCIE_RESET_CONFIG_DEVICE_WAIT_MS waiting time value Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 11/28] PCI: Move link up wait time and max retries macros to pci.h Claudiu
                   ` (17 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Niklas Cassel <cassel@kernel.org>

commit 817f989700fddefa56e5e443e7d138018ca6709d upstream.

Rename PCIE_RESET_CONFIG_DEVICE_WAIT_MS to PCIE_RESET_CONFIG_WAIT_MS.

Suggested-by: Bjorn Helgaas <helgaas@kernel.org>
Signed-off-by: Niklas Cassel <cassel@kernel.org>
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Link: https://patch.msgid.link/20250625102347.1205584-10-cassel@kernel.org
[claudiu.beznea: dropped the changes for
 drivers/pci/controller/plda/pcie-starfive.c because it is not available
 in v5.10 CIP]
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 drivers/pci/pci.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index a391e4db9401..9001851a8ad7 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -24,7 +24,7 @@
  *    completes before sending a Configuration Request to the device
  *    immediately below that Port."
  */
-#define PCIE_RESET_CONFIG_DEVICE_WAIT_MS	100
+#define PCIE_RESET_CONFIG_WAIT_MS	100
 
 extern const unsigned char pcie_link_speed[];
 extern bool pci_early_dump;
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 11/28] PCI: Move link up wait time and max retries macros to pci.h
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (9 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 10/28] PCI: Rename PCIE_RESET_CONFIG_DEVICE_WAIT_MS to PCIE_RESET_CONFIG_WAIT_MS Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 12/28] reset: make shared pulsed reset controls re-triggerable Claudiu
                   ` (16 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Niklas Cassel <cassel@kernel.org>

commit d7467bc72ce4e3f64062017d6c9ae3816e8a7b0e upstream.

Move the LINK_WAIT_SLEEP_MS and LINK_WAIT_MAX_RETRIES macros to pci.h.
Prefix the macros with PCIE_ in order to avoid redefining these for
drivers that already have macros named like this.

No functional changes.

Suggested-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Niklas Cassel <cassel@kernel.org>
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Link: https://patch.msgid.link/20250625102347.1205584-15-cassel@kernel.org
[claudiu.beznea:
 - dropped changes to pcie-designware as the CIP v5.10 uses usleep_range()
   while the original commit uses msleep()
 - fixed conflict in pci.h by keeping only the PCIE_LINK_WAIT_MAX_RETRIES
   and PCIE_LINK_WAIT_SLEEP_MS macros]
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 drivers/pci/pci.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 9001851a8ad7..0ddc1e37a796 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -26,6 +26,10 @@
  */
 #define PCIE_RESET_CONFIG_WAIT_MS	100
 
+/* Parameters for the waiting for link up routine */
+#define PCIE_LINK_WAIT_MAX_RETRIES	10
+#define PCIE_LINK_WAIT_SLEEP_MS		90
+
 extern const unsigned char pcie_link_speed[];
 extern bool pci_early_dump;
 
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 12/28] reset: make shared pulsed reset controls re-triggerable
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (10 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 11/28] PCI: Move link up wait time and max retries macros to pci.h Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-24  9:37   ` Pavel Machek
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 13/28] reset: Add reset_control_bulk API Claudiu
                   ` (15 subsequent siblings)
  27 siblings, 1 reply; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Amjad Ouled-Ameur <aouledameur@baylibre.com>

commit 557acb3d2cd9c82de19f944f6cc967a347735385 upstream.

The current reset framework API does not allow to release what is done by
reset_control_reset(), IOW decrement triggered_count. Add the new
reset_control_rearm() call to do so.

When reset_control_reset() has been called once, the counter
triggered_count, in the reset framework, is incremented i.e the resource
under the reset is in-use and the reset should not be done again.
reset_control_rearm() would be the way to state that the resource is
no longer used and, that from the caller's perspective, the reset can be
fired again if necessary.

Signed-off-by: Amjad Ouled-Ameur <aouledameur@baylibre.com>
Reported-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 drivers/reset/core.c  | 73 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/reset.h |  1 +
 2 files changed, 74 insertions(+)

diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 662867435fbe..4d1cd09096f5 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -208,6 +208,39 @@ static int reset_control_array_reset(struct reset_control_array *resets)
 	return 0;
 }
 
+static int reset_control_array_rearm(struct reset_control_array *resets)
+{
+	struct reset_control *rstc;
+	int i;
+
+	for (i = 0; i < resets->num_rstcs; i++) {
+		rstc = resets->rstc[i];
+
+		if (!rstc)
+			continue;
+
+		if (WARN_ON(IS_ERR(rstc)))
+			return -EINVAL;
+
+		if (rstc->shared) {
+			if (WARN_ON(atomic_read(&rstc->deassert_count) != 0))
+				return -EINVAL;
+		} else {
+			if (!rstc->acquired)
+				return -EPERM;
+		}
+	}
+
+	for (i = 0; i < resets->num_rstcs; i++) {
+		rstc = resets->rstc[i];
+
+		if (rstc && rstc->shared)
+			WARN_ON(atomic_dec_return(&rstc->triggered_count) < 0);
+	}
+
+	return 0;
+}
+
 static int reset_control_array_assert(struct reset_control_array *resets)
 {
 	int ret, i;
@@ -325,6 +358,46 @@ int reset_control_reset(struct reset_control *rstc)
 }
 EXPORT_SYMBOL_GPL(reset_control_reset);
 
+/**
+ * reset_control_rearm - allow shared reset line to be re-triggered"
+ * @rstc: reset controller
+ *
+ * On a shared reset line the actual reset pulse is only triggered once for the
+ * lifetime of the reset_control instance, except if this call is used.
+ *
+ * Calls to this function must be balanced with calls to reset_control_reset,
+ * a warning is thrown in case triggered_count ever dips below 0.
+ *
+ * Consumers must not use reset_control_(de)assert on shared reset lines when
+ * reset_control_reset or reset_control_rearm have been used.
+ *
+ * If rstc is NULL the function will just return 0.
+ */
+int reset_control_rearm(struct reset_control *rstc)
+{
+	if (!rstc)
+		return 0;
+
+	if (WARN_ON(IS_ERR(rstc)))
+		return -EINVAL;
+
+	if (reset_control_is_array(rstc))
+		return reset_control_array_rearm(rstc_to_array(rstc));
+
+	if (rstc->shared) {
+		if (WARN_ON(atomic_read(&rstc->deassert_count) != 0))
+			return -EINVAL;
+
+		WARN_ON(atomic_dec_return(&rstc->triggered_count) < 0);
+	} else {
+		if (!rstc->acquired)
+			return -EPERM;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(reset_control_rearm);
+
 /**
  * reset_control_assert - asserts the reset line
  * @rstc: reset controller
diff --git a/include/linux/reset.h b/include/linux/reset.h
index 13aa754d2269..950e96586f1e 100644
--- a/include/linux/reset.h
+++ b/include/linux/reset.h
@@ -13,6 +13,7 @@ struct reset_control;
 #ifdef CONFIG_RESET_CONTROLLER
 
 int reset_control_reset(struct reset_control *rstc);
+int reset_control_rearm(struct reset_control *rstc);
 int reset_control_assert(struct reset_control *rstc);
 int reset_control_deassert(struct reset_control *rstc);
 int reset_control_status(struct reset_control *rstc);
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 13/28] reset: Add reset_control_bulk API
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (11 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 12/28] reset: make shared pulsed reset controls re-triggerable Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 14/28] of: Add cleanup.h based auto release via __free(device_node) markings Claudiu
                   ` (14 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Philipp Zabel <p.zabel@pengutronix.de>

commit 48d71395896d54eec989179dd265e569fcecb15a upstream.

Follow the clock and regulator subsystems' lead and add a bulk API
for reset controls.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Tested-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Link: https://lore.kernel.org/r/20210314154459.15375-5-digetx@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
[claudiu.beznea: fixed conflict in reset.h by keeping also the code from
 this commit]
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 drivers/reset/core.c  | 215 +++++++++++++++++++++++++++
 include/linux/reset.h | 334 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 549 insertions(+)

diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 4d1cd09096f5..e374539e8511 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -358,6 +358,30 @@ int reset_control_reset(struct reset_control *rstc)
 }
 EXPORT_SYMBOL_GPL(reset_control_reset);
 
+/**
+ * reset_control_bulk_reset - reset the controlled devices in order
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset controls set
+ *
+ * Issue a reset on all provided reset controls, in order.
+ *
+ * See also: reset_control_reset()
+ */
+int reset_control_bulk_reset(int num_rstcs,
+			     struct reset_control_bulk_data *rstcs)
+{
+	int ret, i;
+
+	for (i = 0; i < num_rstcs; i++) {
+		ret = reset_control_reset(rstcs[i].rstc);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(reset_control_bulk_reset);
+
 /**
  * reset_control_rearm - allow shared reset line to be re-triggered"
  * @rstc: reset controller
@@ -461,6 +485,36 @@ int reset_control_assert(struct reset_control *rstc)
 }
 EXPORT_SYMBOL_GPL(reset_control_assert);
 
+/**
+ * reset_control_bulk_assert - asserts the reset lines in order
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset controls set
+ *
+ * Assert the reset lines for all provided reset controls, in order.
+ * If an assertion fails, already asserted resets are deasserted again.
+ *
+ * See also: reset_control_assert()
+ */
+int reset_control_bulk_assert(int num_rstcs,
+			      struct reset_control_bulk_data *rstcs)
+{
+	int ret, i;
+
+	for (i = 0; i < num_rstcs; i++) {
+		ret = reset_control_assert(rstcs[i].rstc);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	while (i--)
+		reset_control_deassert(rstcs[i].rstc);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(reset_control_bulk_assert);
+
 /**
  * reset_control_deassert - deasserts the reset line
  * @rstc: reset controller
@@ -511,6 +565,36 @@ int reset_control_deassert(struct reset_control *rstc)
 }
 EXPORT_SYMBOL_GPL(reset_control_deassert);
 
+/**
+ * reset_control_bulk_deassert - deasserts the reset lines in reverse order
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset controls set
+ *
+ * Deassert the reset lines for all provided reset controls, in reverse order.
+ * If a deassertion fails, already deasserted resets are asserted again.
+ *
+ * See also: reset_control_deassert()
+ */
+int reset_control_bulk_deassert(int num_rstcs,
+				struct reset_control_bulk_data *rstcs)
+{
+	int ret, i;
+
+	for (i = num_rstcs - 1; i >= 0; i--) {
+		ret = reset_control_deassert(rstcs[i].rstc);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	while (i < num_rstcs)
+		reset_control_assert(rstcs[i++].rstc);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(reset_control_bulk_deassert);
+
 /**
  * reset_control_status - returns a negative errno if not supported, a
  * positive value if the reset line is asserted, or zero if the reset
@@ -588,6 +672,36 @@ int reset_control_acquire(struct reset_control *rstc)
 }
 EXPORT_SYMBOL_GPL(reset_control_acquire);
 
+/**
+ * reset_control_bulk_acquire - acquires reset controls for exclusive use
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset controls set
+ *
+ * This is used to explicitly acquire reset controls requested with
+ * reset_control_bulk_get_exclusive_release() for temporary exclusive use.
+ *
+ * See also: reset_control_acquire(), reset_control_bulk_release()
+ */
+int reset_control_bulk_acquire(int num_rstcs,
+			       struct reset_control_bulk_data *rstcs)
+{
+	int ret, i;
+
+	for (i = 0; i < num_rstcs; i++) {
+		ret = reset_control_acquire(rstcs[i].rstc);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	while (i--)
+		reset_control_release(rstcs[i].rstc);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(reset_control_bulk_acquire);
+
 /**
  * reset_control_release() - releases exclusive access to a reset control
  * @rstc: reset control
@@ -610,6 +724,26 @@ void reset_control_release(struct reset_control *rstc)
 }
 EXPORT_SYMBOL_GPL(reset_control_release);
 
+/**
+ * reset_control_bulk_release() - releases exclusive access to reset controls
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset controls set
+ *
+ * Releases exclusive access right to reset controls previously obtained by a
+ * call to reset_control_bulk_acquire().
+ *
+ * See also: reset_control_release(), reset_control_bulk_acquire()
+ */
+void reset_control_bulk_release(int num_rstcs,
+				struct reset_control_bulk_data *rstcs)
+{
+	int i;
+
+	for (i = 0; i < num_rstcs; i++)
+		reset_control_release(rstcs[i].rstc);
+}
+EXPORT_SYMBOL_GPL(reset_control_bulk_release);
+
 static struct reset_control *__reset_control_get_internal(
 				struct reset_controller_dev *rcdev,
 				unsigned int index, bool shared, bool acquired)
@@ -820,6 +954,32 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id,
 }
 EXPORT_SYMBOL_GPL(__reset_control_get);
 
+int __reset_control_bulk_get(struct device *dev, int num_rstcs,
+			     struct reset_control_bulk_data *rstcs,
+			     bool shared, bool optional, bool acquired)
+{
+	int ret, i;
+
+	for (i = 0; i < num_rstcs; i++) {
+		rstcs[i].rstc = __reset_control_get(dev, rstcs[i].id, 0,
+						    shared, optional, acquired);
+		if (IS_ERR(rstcs[i].rstc)) {
+			ret = PTR_ERR(rstcs[i].rstc);
+			goto err;
+		}
+	}
+
+	return 0;
+
+err:
+	mutex_lock(&reset_list_mutex);
+	while (i--)
+		__reset_control_put_internal(rstcs[i].rstc);
+	mutex_unlock(&reset_list_mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(__reset_control_bulk_get);
+
 static void reset_control_array_put(struct reset_control_array *resets)
 {
 	int i;
@@ -851,6 +1011,23 @@ void reset_control_put(struct reset_control *rstc)
 }
 EXPORT_SYMBOL_GPL(reset_control_put);
 
+/**
+ * reset_control_bulk_put - free the reset controllers
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset controls set
+ */
+void reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs)
+{
+	mutex_lock(&reset_list_mutex);
+	while (num_rstcs--) {
+		if (IS_ERR_OR_NULL(rstcs[num_rstcs].rstc))
+			continue;
+		__reset_control_put_internal(rstcs[num_rstcs].rstc);
+	}
+	mutex_unlock(&reset_list_mutex);
+}
+EXPORT_SYMBOL_GPL(reset_control_bulk_put);
+
 static void devm_reset_control_release(struct device *dev, void *res)
 {
 	reset_control_put(*(struct reset_control **)res);
@@ -880,6 +1057,44 @@ struct reset_control *__devm_reset_control_get(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(__devm_reset_control_get);
 
+struct reset_control_bulk_devres {
+	int num_rstcs;
+	struct reset_control_bulk_data *rstcs;
+};
+
+static void devm_reset_control_bulk_release(struct device *dev, void *res)
+{
+	struct reset_control_bulk_devres *devres = res;
+
+	reset_control_bulk_put(devres->num_rstcs, devres->rstcs);
+}
+
+int __devm_reset_control_bulk_get(struct device *dev, int num_rstcs,
+				  struct reset_control_bulk_data *rstcs,
+				  bool shared, bool optional, bool acquired)
+{
+	struct reset_control_bulk_devres *ptr;
+	int ret;
+
+	ptr = devres_alloc(devm_reset_control_bulk_release, sizeof(*ptr),
+			   GFP_KERNEL);
+	if (!ptr)
+		return -ENOMEM;
+
+	ret = __reset_control_bulk_get(dev, num_rstcs, rstcs, shared, optional, acquired);
+	if (ret < 0) {
+		devres_free(ptr);
+		return ret;
+	}
+
+	ptr->num_rstcs = num_rstcs;
+	ptr->rstcs = rstcs;
+	devres_add(dev, ptr);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(__devm_reset_control_bulk_get);
+
 /**
  * device_reset - find reset controller associated with the device
  *                and perform reset
diff --git a/include/linux/reset.h b/include/linux/reset.h
index 950e96586f1e..346b9340ec8f 100644
--- a/include/linux/reset.h
+++ b/include/linux/reset.h
@@ -10,6 +10,21 @@ struct device;
 struct device_node;
 struct reset_control;
 
+/**
+ * struct reset_control_bulk_data - Data used for bulk reset control operations.
+ *
+ * @id: reset control consumer ID
+ * @rstc: struct reset_control * to store the associated reset control
+ *
+ * The reset APIs provide a series of reset_control_bulk_*() API calls as
+ * a convenience to consumers which require multiple reset controls.
+ * This structure is used to manage data for these calls.
+ */
+struct reset_control_bulk_data {
+	const char			*id;
+	struct reset_control		*rstc;
+};
+
 #ifdef CONFIG_RESET_CONTROLLER
 
 int reset_control_reset(struct reset_control *rstc);
@@ -20,6 +35,12 @@ int reset_control_status(struct reset_control *rstc);
 int reset_control_acquire(struct reset_control *rstc);
 void reset_control_release(struct reset_control *rstc);
 
+int reset_control_bulk_reset(int num_rstcs, struct reset_control_bulk_data *rstcs);
+int reset_control_bulk_assert(int num_rstcs, struct reset_control_bulk_data *rstcs);
+int reset_control_bulk_deassert(int num_rstcs, struct reset_control_bulk_data *rstcs);
+int reset_control_bulk_acquire(int num_rstcs, struct reset_control_bulk_data *rstcs);
+void reset_control_bulk_release(int num_rstcs, struct reset_control_bulk_data *rstcs);
+
 struct reset_control *__of_reset_control_get(struct device_node *node,
 				     const char *id, int index, bool shared,
 				     bool optional, bool acquired);
@@ -27,10 +48,18 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id,
 					  int index, bool shared,
 					  bool optional, bool acquired);
 void reset_control_put(struct reset_control *rstc);
+int __reset_control_bulk_get(struct device *dev, int num_rstcs,
+			     struct reset_control_bulk_data *rstcs,
+			     bool shared, bool optional, bool acquired);
+void reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs);
+
 int __device_reset(struct device *dev, bool optional);
 struct reset_control *__devm_reset_control_get(struct device *dev,
 				     const char *id, int index, bool shared,
 				     bool optional, bool acquired);
+int __devm_reset_control_bulk_get(struct device *dev, int num_rstcs,
+				  struct reset_control_bulk_data *rstcs,
+				  bool shared, bool optional, bool acquired);
 
 struct reset_control *devm_reset_control_array_get(struct device *dev,
 						   bool shared, bool optional);
@@ -96,6 +125,48 @@ static inline struct reset_control *__reset_control_get(
 	return optional ? NULL : ERR_PTR(-ENOTSUPP);
 }
 
+static inline int
+reset_control_bulk_reset(int num_rstcs, struct reset_control_bulk_data *rstcs)
+{
+	return 0;
+}
+
+static inline int
+reset_control_bulk_assert(int num_rstcs, struct reset_control_bulk_data *rstcs)
+{
+	return 0;
+}
+
+static inline int
+reset_control_bulk_deassert(int num_rstcs, struct reset_control_bulk_data *rstcs)
+{
+	return 0;
+}
+
+static inline int
+reset_control_bulk_acquire(int num_rstcs, struct reset_control_bulk_data *rstcs)
+{
+	return 0;
+}
+
+static inline void
+reset_control_bulk_release(int num_rstcs, struct reset_control_bulk_data *rstcs)
+{
+}
+
+static inline int
+__reset_control_bulk_get(struct device *dev, int num_rstcs,
+			 struct reset_control_bulk_data *rstcs,
+			 bool shared, bool optional, bool acquired)
+{
+	return optional ? 0 : -EOPNOTSUPP;
+}
+
+static inline void
+reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs)
+{
+}
+
 static inline struct reset_control *__devm_reset_control_get(
 					struct device *dev, const char *id,
 					int index, bool shared, bool optional,
@@ -104,6 +175,14 @@ static inline struct reset_control *__devm_reset_control_get(
 	return optional ? NULL : ERR_PTR(-ENOTSUPP);
 }
 
+static inline int
+__devm_reset_control_bulk_get(struct device *dev, int num_rstcs,
+			      struct reset_control_bulk_data *rstcs,
+			      bool shared, bool optional, bool acquired)
+{
+	return optional ? 0 : -EOPNOTSUPP;
+}
+
 static inline struct reset_control *
 devm_reset_control_array_get(struct device *dev, bool shared, bool optional)
 {
@@ -155,6 +234,23 @@ __must_check reset_control_get_exclusive(struct device *dev, const char *id)
 	return __reset_control_get(dev, id, 0, false, false, true);
 }
 
+/**
+ * reset_control_bulk_get_exclusive - Lookup and obtain exclusive references to
+ *                                    multiple reset controllers.
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Fills the rstcs array with pointers to exclusive reset controls and
+ * returns 0, or an IS_ERR() condition containing errno.
+ */
+static inline int __must_check
+reset_control_bulk_get_exclusive(struct device *dev, int num_rstcs,
+				 struct reset_control_bulk_data *rstcs)
+{
+	return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, true);
+}
+
 /**
  * reset_control_get_exclusive_released - Lookup and obtain a temoprarily
  *                                        exclusive reference to a reset
@@ -176,6 +272,48 @@ __must_check reset_control_get_exclusive_released(struct device *dev,
 	return __reset_control_get(dev, id, 0, false, false, false);
 }
 
+/**
+ * reset_control_bulk_get_exclusive_released - Lookup and obtain temporarily
+ *                                    exclusive references to multiple reset
+ *                                    controllers.
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Fills the rstcs array with pointers to exclusive reset controls and
+ * returns 0, or an IS_ERR() condition containing errno.
+ * reset-controls returned by this function must be acquired via
+ * reset_control_bulk_acquire() before they can be used and should be released
+ * via reset_control_bulk_release() afterwards.
+ */
+static inline int __must_check
+reset_control_bulk_get_exclusive_released(struct device *dev, int num_rstcs,
+					  struct reset_control_bulk_data *rstcs)
+{
+	return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, false);
+}
+
+/**
+ * reset_control_bulk_get_optional_exclusive_released - Lookup and obtain optional
+ *                                    temporarily exclusive references to multiple
+ *                                    reset controllers.
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Optional variant of reset_control_bulk_get_exclusive_released(). If the
+ * requested reset is not specified in the device tree, this function returns 0
+ * instead of an error and missing rtsc is set to NULL.
+ *
+ * See reset_control_bulk_get_exclusive_released() for more information.
+ */
+static inline int __must_check
+reset_control_bulk_get_optional_exclusive_released(struct device *dev, int num_rstcs,
+						   struct reset_control_bulk_data *rstcs)
+{
+	return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, false);
+}
+
 /**
  * reset_control_get_shared - Lookup and obtain a shared reference to a
  *                            reset controller.
@@ -204,6 +342,23 @@ static inline struct reset_control *reset_control_get_shared(
 	return __reset_control_get(dev, id, 0, true, false, false);
 }
 
+/**
+ * reset_control_bulk_get_shared - Lookup and obtain shared references to
+ *                                 multiple reset controllers.
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Fills the rstcs array with pointers to shared reset controls and
+ * returns 0, or an IS_ERR() condition containing errno.
+ */
+static inline int __must_check
+reset_control_bulk_get_shared(struct device *dev, int num_rstcs,
+			      struct reset_control_bulk_data *rstcs)
+{
+	return __reset_control_bulk_get(dev, num_rstcs, rstcs, true, false, false);
+}
+
 /**
  * reset_control_get_optional_exclusive - optional reset_control_get_exclusive()
  * @dev: device to be reset by the controller
@@ -221,6 +376,26 @@ static inline struct reset_control *reset_control_get_optional_exclusive(
 	return __reset_control_get(dev, id, 0, false, true, true);
 }
 
+/**
+ * reset_control_bulk_get_optional_exclusive - optional
+ *                                             reset_control_bulk_get_exclusive()
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Optional variant of reset_control_bulk_get_exclusive(). If any of the
+ * requested resets are not specified in the device tree, this function sets
+ * them to NULL instead of returning an error.
+ *
+ * See reset_control_bulk_get_exclusive() for more information.
+ */
+static inline int __must_check
+reset_control_bulk_get_optional_exclusive(struct device *dev, int num_rstcs,
+					  struct reset_control_bulk_data *rstcs)
+{
+	return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, true);
+}
+
 /**
  * reset_control_get_optional_shared - optional reset_control_get_shared()
  * @dev: device to be reset by the controller
@@ -238,6 +413,26 @@ static inline struct reset_control *reset_control_get_optional_shared(
 	return __reset_control_get(dev, id, 0, true, true, false);
 }
 
+/**
+ * reset_control_bulk_get_optional_shared - optional
+ *                                             reset_control_bulk_get_shared()
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Optional variant of reset_control_bulk_get_shared(). If the requested resets
+ * are not specified in the device tree, this function sets them to NULL
+ * instead of returning an error.
+ *
+ * See reset_control_bulk_get_shared() for more information.
+ */
+static inline int __must_check
+reset_control_bulk_get_optional_shared(struct device *dev, int num_rstcs,
+				       struct reset_control_bulk_data *rstcs)
+{
+	return __reset_control_bulk_get(dev, num_rstcs, rstcs, true, true, false);
+}
+
 /**
  * of_reset_control_get_exclusive - Lookup and obtain an exclusive reference
  *                                  to a reset controller.
@@ -363,6 +558,26 @@ __must_check devm_reset_control_get_exclusive(struct device *dev,
 	return __devm_reset_control_get(dev, id, 0, false, false, true);
 }
 
+/**
+ * devm_reset_control_bulk_get_exclusive - resource managed
+ *                                         reset_control_bulk_get_exclusive()
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Managed reset_control_bulk_get_exclusive(). For reset controllers returned
+ * from this function, reset_control_put() is called automatically on driver
+ * detach.
+ *
+ * See reset_control_bulk_get_exclusive() for more information.
+ */
+static inline int __must_check
+devm_reset_control_bulk_get_exclusive(struct device *dev, int num_rstcs,
+				      struct reset_control_bulk_data *rstcs)
+{
+	return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, true);
+}
+
 /**
  * devm_reset_control_get_exclusive_released - resource managed
  *                                             reset_control_get_exclusive_released()
@@ -382,6 +597,65 @@ __must_check devm_reset_control_get_exclusive_released(struct device *dev,
 	return __devm_reset_control_get(dev, id, 0, false, false, false);
 }
 
+/**
+ * devm_reset_control_bulk_get_exclusive_released - resource managed
+ *                                                  reset_control_bulk_get_exclusive_released()
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Managed reset_control_bulk_get_exclusive_released(). For reset controllers
+ * returned from this function, reset_control_put() is called automatically on
+ * driver detach.
+ *
+ * See reset_control_bulk_get_exclusive_released() for more information.
+ */
+static inline int __must_check
+devm_reset_control_bulk_get_exclusive_released(struct device *dev, int num_rstcs,
+					       struct reset_control_bulk_data *rstcs)
+{
+	return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, false);
+}
+
+/**
+ * devm_reset_control_get_optional_exclusive_released - resource managed
+ *                                                      reset_control_get_optional_exclusive_released()
+ * @dev: device to be reset by the controller
+ * @id: reset line name
+ *
+ * Managed-and-optional variant of reset_control_get_exclusive_released(). For
+ * reset controllers returned from this function, reset_control_put() is called
+ * automatically on driver detach.
+ *
+ * See reset_control_get_exclusive_released() for more information.
+ */
+static inline struct reset_control *
+__must_check devm_reset_control_get_optional_exclusive_released(struct device *dev,
+								const char *id)
+{
+	return __devm_reset_control_get(dev, id, 0, false, true, false);
+}
+
+/**
+ * devm_reset_control_bulk_get_optional_exclusive_released - resource managed
+ *                                                           reset_control_bulk_optional_get_exclusive_released()
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Managed reset_control_bulk_optional_get_exclusive_released(). For reset
+ * controllers returned from this function, reset_control_put() is called
+ * automatically on driver detach.
+ *
+ * See reset_control_bulk_optional_get_exclusive_released() for more information.
+ */
+static inline int __must_check
+devm_reset_control_bulk_get_optional_exclusive_released(struct device *dev, int num_rstcs,
+							struct reset_control_bulk_data *rstcs)
+{
+	return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, false);
+}
+
 /**
  * devm_reset_control_get_shared - resource managed reset_control_get_shared()
  * @dev: device to be reset by the controller
@@ -397,6 +671,26 @@ static inline struct reset_control *devm_reset_control_get_shared(
 	return __devm_reset_control_get(dev, id, 0, true, false, false);
 }
 
+/**
+ * devm_reset_control_bulk_get_shared - resource managed
+ *                                      reset_control_bulk_get_shared()
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Managed reset_control_bulk_get_shared(). For reset controllers returned
+ * from this function, reset_control_put() is called automatically on driver
+ * detach.
+ *
+ * See reset_control_bulk_get_shared() for more information.
+ */
+static inline int __must_check
+devm_reset_control_bulk_get_shared(struct device *dev, int num_rstcs,
+				   struct reset_control_bulk_data *rstcs)
+{
+	return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, true, false, false);
+}
+
 /**
  * devm_reset_control_get_optional_exclusive - resource managed
  *                                             reset_control_get_optional_exclusive()
@@ -415,6 +709,26 @@ static inline struct reset_control *devm_reset_control_get_optional_exclusive(
 	return __devm_reset_control_get(dev, id, 0, false, true, true);
 }
 
+/**
+ * devm_reset_control_bulk_get_optional_exclusive - resource managed
+ *                                                  reset_control_bulk_get_optional_exclusive()
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Managed reset_control_bulk_get_optional_exclusive(). For reset controllers
+ * returned from this function, reset_control_put() is called automatically on
+ * driver detach.
+ *
+ * See reset_control_bulk_get_optional_exclusive() for more information.
+ */
+static inline int __must_check
+devm_reset_control_bulk_get_optional_exclusive(struct device *dev, int num_rstcs,
+					       struct reset_control_bulk_data *rstcs)
+{
+	return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, true, false, true);
+}
+
 /**
  * devm_reset_control_get_optional_shared - resource managed
  *                                          reset_control_get_optional_shared()
@@ -433,6 +747,26 @@ static inline struct reset_control *devm_reset_control_get_optional_shared(
 	return __devm_reset_control_get(dev, id, 0, true, true, false);
 }
 
+/**
+ * devm_reset_control_bulk_get_optional_shared - resource managed
+ *                                               reset_control_bulk_get_optional_shared()
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Managed reset_control_bulk_get_optional_shared(). For reset controllers
+ * returned from this function, reset_control_put() is called automatically on
+ * driver detach.
+ *
+ * See reset_control_bulk_get_optional_shared() for more information.
+ */
+static inline int __must_check
+devm_reset_control_bulk_get_optional_shared(struct device *dev, int num_rstcs,
+					    struct reset_control_bulk_data *rstcs)
+{
+	return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, true, true, false);
+}
+
 /**
  * devm_reset_control_get_exclusive_by_index - resource managed
  *                                             reset_control_get_exclusive()
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 14/28] of: Add cleanup.h based auto release via __free(device_node) markings
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (12 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 13/28] reset: Add reset_control_bulk API Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 15/28] of/irq: Allow matching of an interrupt-map local to an interrupt controller Claudiu
                   ` (13 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Jonathan Cameron <Jonathan.Cameron@huawei.com>

commit 9448e55d032d99af8e23487f51a542d51b2f1a48 upstream.

The recent addition of scope based cleanup support to the kernel
provides a convenient tool to reduce the chances of leaking reference
counts where of_node_put() should have been called in an error path.

This enables
	struct device_node *child __free(device_node) = NULL;

	for_each_child_of_node(np, child) {
		if (test)
			return test;
	}

with no need for a manual call of of_node_put().
A following patch will reduce the scope of the child variable to the
for loop, to avoid an issues with ordering of autocleanup, and make it
obvious when this assigned a non NULL value.

In this simple example the gains are small but there are some very
complex error handling cases buried in these loops that will be
greatly simplified by enabling early returns with out the need
for this manual of_node_put() call.

Note that there are coccinelle checks in
scripts/coccinelle/iterators/for_each_child.cocci to detect a failure
to call of_node_put(). This new approach does not cause false positives.
Longer term we may want to add scripting to check this new approach is
done correctly with no double of_node_put() calls being introduced due
to the auto cleanup. It may also be useful to script finding places
this new approach is useful.

Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Link: https://lore.kernel.org/r/20240225142714.286440-2-jic23@kernel.org
Signed-off-by: Rob Herring <robh@kernel.org>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 include/linux/of.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/of.h b/include/linux/of.h
index 65c0e3105809..5f4dd8db7a67 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -13,6 +13,7 @@
  */
 #include <linux/types.h>
 #include <linux/bitops.h>
+#include <linux/cleanup.h>
 #include <linux/errno.h>
 #include <linux/kobject.h>
 #include <linux/mod_devicetable.h>
@@ -128,6 +129,7 @@ static inline struct device_node *of_node_get(struct device_node *node)
 }
 static inline void of_node_put(struct device_node *node) { }
 #endif /* !CONFIG_OF_DYNAMIC */
+DEFINE_FREE(device_node, struct device_node *, if (_T) of_node_put(_T))
 
 /* Pointer for first entry in chain of all nodes. */
 extern struct device_node *of_root;
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 15/28] of/irq: Allow matching of an interrupt-map local to an interrupt controller
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (13 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 14/28] of: Add cleanup.h based auto release via __free(device_node) markings Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 16/28] of/irq: Update the out_irq->np before returning success Claudiu
                   ` (12 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Marc Zyngier <maz@kernel.org>

commit c12346543a7850d20ff70923ce12b60ef81a8416 upstream.

of_irq_parse_raw() has a baked assumption that if a node has an
interrupt-controller property, it cannot possibly also have an
interrupt-map property (the latter being ignored).

This seems to be an odd behaviour, and there is no reason why we should
avoid supporting this use case. This is specially useful when a PCI root
port acts as an interrupt controller for PCI endpoints, such as this:

  pcie0: pcie@690000000 {
      [...]
      port00: pci@0,0 {
	  device_type = "pci";
	  [...]
	  #address-cells = <3>;

	  interrupt-controller;
	  #interrupt-cells = <1>;

	  interrupt-map-mask = <0 0 0 7>;
	  interrupt-map = <0 0 0 1 &port00 0 0 0 0>,
			  <0 0 0 2 &port00 0 0 0 1>,
			  <0 0 0 3 &port00 0 0 0 2>,
			  <0 0 0 4 &port00 0 0 0 3>;
      };
  };

Handle it by detecting that we have an interrupt-map early in the parsing,
and special case the situation where the phandle in the interrupt map
refers to the current node (which is the interesting case here).

Link: https://lore.kernel.org/r/20210929163847.2807812-3-maz@kernel.org
Tested-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Rob Herring <robh@kernel.org>
[claudiu.beznea: made the code in this patch be executable only for the
 Renesas RZ/G3S SoC]
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 drivers/of/irq.c | 30 ++++++++++++++++++++++++------
 1 file changed, 24 insertions(+), 6 deletions(-)

diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index fe88a23240f5..691e72598f70 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -102,6 +102,14 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
 	const __be32 *tmp, *imap, *imask, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = cpu_to_be32(~0) };
 	u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
 	int imaplen, match, i, rc = -EINVAL;
+	static const char * const renesas_socs[] = {
+		"renesas,r9a08g045", /* Renesas RZ/G3S */
+		NULL
+	};
+	bool renesas = false;
+
+	if (of_machine_compatible_match(renesas_socs))
+		renesas = true;
 
 #ifdef DEBUG
 	of_print_phandle_args("of_irq_parse_raw: ", out_irq);
@@ -160,12 +168,17 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
 
 	/* Now start the actual "proper" walk of the interrupt tree */
 	while (ipar != NULL) {
-		/* Now check if cursor is an interrupt-controller and if it is
-		 * then we are done
+		/*
+		 * Now check if cursor is an interrupt-controller and
+		 * if it is then we are done, unless there is an
+		 * interrupt-map which takes precedence.
 		 */
+		imap = of_get_property(ipar, "interrupt-map", &imaplen);
 		if (of_property_read_bool(ipar, "interrupt-controller")) {
-			pr_debug(" -> got it !\n");
-			return 0;
+			if ((renesas && !imap) || !renesas) {
+				pr_debug(" -> got it !\n");
+				return 0;
+			}
 		}
 
 		/*
@@ -177,8 +190,6 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
 			goto fail;
 		}
 
-		/* Now look for an interrupt-map */
-		imap = of_get_property(ipar, "interrupt-map", &imaplen);
 		/* No interrupt map, check for an interrupt parent */
 		if (imap == NULL) {
 			pr_debug(" -> no map, getting parent\n");
@@ -259,6 +270,13 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
 		out_irq->args_count = intsize = newintsize;
 		addrsize = newaddrsize;
 
+		if (renesas) {
+			if (ipar == newpar) {
+				pr_debug("%pOF interrupt-map entry to self\n", ipar);
+				return 0;
+			}
+		}
+
 	skiplevel:
 		/* Iterate again with new parent */
 		out_irq->np = newpar;
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 16/28] of/irq: Update the out_irq->np before returning success
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (14 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 15/28] of/irq: Allow matching of an interrupt-map local to an interrupt controller Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 17/28] dt-bindings: PCI: Add Renesas RZ/G3S PCIe controller binding Claudiu
                   ` (11 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

Upstream commit c1e459d72448 ("of/irq: Factor out parsing of interrupt-map
parent phandle+args from of_irq_parse_raw()") refactored the parsing of the
interrupt-map parent phandle and updated out_irq->np before returning
success.

This change allows declaring interrupt-map and interrupt-map-mask on the
PCIe device tree nodes representing the host controllers, pointing to
itself, making it possible to reuse the RZ/G3S PCIe upstream device tree
format in v5.10 CIP.

Without this change, interrupt-map and interrupt-map-mask would have to be
described on the PCIe port DT node, which would break the DT ABI.

Since commit c1e459d72448 ("of/irq: Factor out parsing of interrupt-map
parent phandle+args from of_irq_parse_raw()") spans multiple functions,
and to keep this backport minimal, only the relevant lines are updated.
The functional changes are applied only for the Renesas RZ/G3S SoC.

Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 drivers/of/irq.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 691e72598f70..50f998222569 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -271,6 +271,7 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
 		addrsize = newaddrsize;
 
 		if (renesas) {
+			out_irq->np = newpar;
 			if (ipar == newpar) {
 				pr_debug("%pOF interrupt-map entry to self\n", ipar);
 				return 0;
@@ -279,8 +280,10 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
 
 	skiplevel:
 		/* Iterate again with new parent */
-		out_irq->np = newpar;
-		pr_debug(" -> new parent: %pOF\n", newpar);
+		if (!renesas) {
+			out_irq->np = newpar;
+			pr_debug(" -> new parent: %pOF\n", newpar);
+		}
 		of_node_put(ipar);
 		ipar = newpar;
 		newpar = NULL;
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 17/28] dt-bindings: PCI: Add Renesas RZ/G3S PCIe controller binding
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (15 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 16/28] of/irq: Update the out_irq->np before returning success Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 18/28] PCI: Add Renesas RZ/G3S host controller driver Claudiu
                   ` (10 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

commit e7534e790557e9ee18a2c497dc89a6b31e435e48 upstream.

The PCIe IP available on the Renesas RZ/G3S complies with the PCI Express
Base Specification 4.0. It is designed for root complex applications and
features a single-lane (x1) implementation. Add binding documentation for
it.

Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Link: https://patch.msgid.link/20251119143523.977085-2-claudiu.beznea.uj@bp.renesas.com
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 .../bindings/pci/renesas,r9a08g045-pcie.yaml  | 249 ++++++++++++++++++
 1 file changed, 249 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/renesas,r9a08g045-pcie.yaml

diff --git a/Documentation/devicetree/bindings/pci/renesas,r9a08g045-pcie.yaml b/Documentation/devicetree/bindings/pci/renesas,r9a08g045-pcie.yaml
new file mode 100644
index 000000000000..d668782546a2
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/renesas,r9a08g045-pcie.yaml
@@ -0,0 +1,249 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pci/renesas,r9a08g045-pcie.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas RZ/G3S PCIe host controller
+
+maintainers:
+  - Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+
+description:
+  Renesas RZ/G3S PCIe host controller complies with PCIe Base Specification
+  4.0 and supports up to 5 GT/s (Gen2).
+
+properties:
+  compatible:
+    const: renesas,r9a08g045-pcie # RZ/G3S
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    items:
+      - description: System error interrupt
+      - description: System error on correctable error interrupt
+      - description: System error on non-fatal error interrupt
+      - description: System error on fatal error interrupt
+      - description: AXI error interrupt
+      - description: INTA interrupt
+      - description: INTB interrupt
+      - description: INTC interrupt
+      - description: INTD interrupt
+      - description: MSI interrupt
+      - description: Link bandwidth interrupt
+      - description: PME interrupt
+      - description: DMA interrupt
+      - description: PCIe event interrupt
+      - description: Message interrupt
+      - description: All interrupts
+
+  interrupt-names:
+    items:
+      - description: serr
+      - description: ser_cor
+      - description: serr_nonfatal
+      - description: serr_fatal
+      - description: axi_err
+      - description: inta
+      - description: intb
+      - description: intc
+      - description: intd
+      - description: msi
+      - description: link_bandwidth
+      - description: pm_pme
+      - description: dma
+      - description: pcie_evt
+      - description: msg
+      - description: all
+
+  interrupt-controller: true
+
+  clocks:
+    items:
+      - description: System clock
+      - description: PM control clock
+
+  clock-names:
+    items:
+      - description: aclk
+      - description: pm
+
+  resets:
+    items:
+      - description: AXI2PCIe Bridge reset
+      - description: Data link layer/transaction layer reset
+      - description: Transaction layer (ACLK domain) reset
+      - description: Transaction layer (PCLK domain) reset
+      - description: Physical layer reset
+      - description: Configuration register reset
+      - description: Configuration register reset
+
+  reset-names:
+    items:
+      - description: aresetn
+      - description: rst_b
+      - description: rst_gp_b
+      - description: rst_ps_b
+      - description: rst_rsm_b
+      - description: rst_cfg_b
+      - description: rst_load_b
+
+  power-domains:
+    maxItems: 1
+
+  dma-ranges:
+    description:
+      A single range for the inbound memory region.
+    maxItems: 1
+
+  renesas,sysc:
+    description: |
+      System controller registers control and monitor various PCIe
+      functionalities.
+
+      Control:
+      - transition to L1 state
+      - receiver termination settings
+      - RST_RSM_B signal
+
+      Monitor:
+      - clkl1pm clock request state
+      - power off information in L2 state
+      - errors (fatal, non-fatal, correctable)
+    $ref: /schemas/types.yaml#/definitions/phandle
+
+patternProperties:
+  "^pcie@0,[0-0]$":
+    type: object
+    allOf:
+      - $ref: /schemas/pci/pci-pci-bridge.yaml#
+
+    properties:
+      reg:
+        maxItems: 1
+
+      vendor-id:
+        const: 0x1912
+
+      device-id:
+        const: 0x0033
+
+      clocks:
+        items:
+          - description: Reference clock
+
+      clock-names:
+        items:
+          - const: ref
+
+    required:
+      - device_type
+      - vendor-id
+      - device-id
+      - clocks
+      - clock-names
+
+    unevaluatedProperties: false
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - interrupts
+  - interrupt-names
+  - interrupt-map
+  - interrupt-map-mask
+  - interrupt-controller
+  - power-domains
+  - "#address-cells"
+  - "#size-cells"
+  - "#interrupt-cells"
+  - renesas,sysc
+
+allOf:
+  - $ref: /schemas/pci/pci-host-bridge.yaml#
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/r9a08g045-cpg.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    bus {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        pcie@11e40000 {
+            compatible = "renesas,r9a08g045-pcie";
+            reg = <0 0x11e40000 0 0x10000>;
+            ranges = <0x02000000 0 0x30000000 0 0x30000000 0 0x08000000>;
+            /* Map all possible DRAM ranges (4 GB). */
+            dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 1 0x00000000>;
+            bus-range = <0x0 0xff>;
+            interrupts = <GIC_SPI 395 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 396 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 397 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 398 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 399 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 401 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 402 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 403 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 404 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 405 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 409 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 410 IRQ_TYPE_LEVEL_HIGH>;
+            interrupt-names = "serr", "serr_cor", "serr_nonfatal",
+                              "serr_fatal", "axi_err", "inta",
+                              "intb", "intc", "intd", "msi",
+                              "link_bandwidth", "pm_pme", "dma",
+                              "pcie_evt", "msg", "all";
+            #interrupt-cells = <1>;
+            interrupt-controller;
+            interrupt-map-mask = <0 0 0 7>;
+            interrupt-map = <0 0 0 1 &pcie 0 0 0 0>, /* INTA */
+                            <0 0 0 2 &pcie 0 0 0 1>, /* INTB */
+                            <0 0 0 3 &pcie 0 0 0 2>, /* INTC */
+                            <0 0 0 4 &pcie 0 0 0 3>; /* INTD */
+            clocks = <&cpg CPG_MOD R9A08G045_PCI_ACLK>,
+                     <&cpg CPG_MOD R9A08G045_PCI_CLKL1PM>;
+            clock-names = "aclk", "pm";
+            resets = <&cpg R9A08G045_PCI_ARESETN>,
+                     <&cpg R9A08G045_PCI_RST_B>,
+                     <&cpg R9A08G045_PCI_RST_GP_B>,
+                     <&cpg R9A08G045_PCI_RST_PS_B>,
+                     <&cpg R9A08G045_PCI_RST_RSM_B>,
+                     <&cpg R9A08G045_PCI_RST_CFG_B>,
+                     <&cpg R9A08G045_PCI_RST_LOAD_B>;
+            reset-names = "aresetn", "rst_b", "rst_gp_b", "rst_ps_b",
+                          "rst_rsm_b", "rst_cfg_b", "rst_load_b";
+            power-domains = <&cpg>;
+            device_type = "pci";
+            #address-cells = <3>;
+            #size-cells = <2>;
+            renesas,sysc = <&sysc>;
+
+            pcie@0,0 {
+                reg = <0x0 0x0 0x0 0x0 0x0>;
+                ranges;
+                clocks = <&versa3 5>;
+                clock-names = "ref";
+                device_type = "pci";
+                vendor-id = <0x1912>;
+                device-id = <0x0033>;
+                #address-cells = <3>;
+                #size-cells = <2>;
+            };
+        };
+    };
+
+...
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 18/28] PCI: Add Renesas RZ/G3S host controller driver
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (16 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 17/28] dt-bindings: PCI: Add Renesas RZ/G3S PCIe controller binding Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 19/28] PCI: rzg3s-host: Initialize MSI status bitmap before use Claudiu
                   ` (9 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

commit 7ef502fb35b283e0f85ed7b34e2d963343981a8c upstream.

The Renesas RZ/G3S features a PCIe IP that complies with the PCI Express
Base Specification 4.0 and supports speeds of up to 5 GT/s. It functions
only as a root complex, with a single-lane (x1) configuration. The
controller includes Type 1 configuration registers, as well as IP
specific registers (called AXI registers) required for various adjustments.

Hardware manual can be downloaded from the address in the "Link" section.
The following steps should be followed to access the manual:
1/ Click the "User Manual" button
2/ Click "Confirm"; this will start downloading an archive
3/ Open the downloaded archive
4/ Navigate to r01uh1014ej*-rzg3s-users-manual-hardware -> Deliverables
5/ Open the file r01uh1014ej*-rzg3s.pdf

Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Link: https://www.renesas.com/en/products/rz-g3s?queryID=695cc067c2d89e3f271d43656ede4d12
Link: https://patch.msgid.link/20251119143523.977085-3-claudiu.beznea.uj@bp.renesas.com
[claudiu.beznea:
 - fixed conflict in Kconfig by keeping only the PCIE_RENESAS_RZG3S_HOST
   entry
 - dropped irq-msi-lib.h as it is not available in v5.10 CIP; with it the
   MSI domain (allocation) code was adjusted as follows:
 -- rzg3s_pcie_msi_parent_ops was dropped along with its flags
 -- rzg3s_pci_msi_top_chip was added along with its ops implementation
 -- the rzg3s_pcie_msi_info was added
 -- rzg3s_pcie_msi_allocated_domain() was adjusted to allocate the MSI
    domain using the helpers available in v5.10 CIP
 -- rzg3s_pcie_msi_irq() was adjusted to use irq_find_mapping() and
    generic_handle_irq(); along with it the MSI IRQ is cheched for
    mapping before callng generic_handle_irq() for it
 -- the teardown path was adjusted to remove the MSI parent IRQ domain
 - for loops were adjusted to avoid compilation error like "loop initial
   declarations are only allowed in C99 or C11 mode"
 - scoped_guard() for mutex from rzg3s_pcie_msi_domain_alloc() was
   replaced with mutex_lock()/mutex_unlock()
 - msi_create_parent_irq_domain() was replaced with
   pci_msi_create_irq_domain() as the former is not available in v5.10
   CIP
 - devm_mutex_init() was replaced with mutex_init() and
   devm_add_action_or_reset()
 - replaced NOIRQ_SYSTEM_SLEEP_PM_OPS() with
   SET_NOIRQ_SYSTEM_SLEEP_PM_OPS()]
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 MAINTAINERS                              |    8 +
 drivers/pci/controller/Kconfig           |    9 +
 drivers/pci/controller/Makefile          |    1 +
 drivers/pci/controller/pcie-rzg3s-host.c | 1801 ++++++++++++++++++++++
 4 files changed, 1819 insertions(+)
 create mode 100644 drivers/pci/controller/pcie-rzg3s-host.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 99cf07744e82..5288c9c53b61 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13630,6 +13630,14 @@ L:	linux-arm-msm@vger.kernel.org
 S:	Maintained
 F:	drivers/pci/controller/dwc/*qcom*
 
+PCIE DRIVER FOR RENESAS RZ/G3S SERIES
+M:	Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+L:	linux-pci@vger.kernel.org
+L:	linux-renesas-soc@vger.kernel.org
+S:	Supported
+F:	Documentation/devicetree/bindings/pci/renesas,r9a08g045-pcie.yaml
+F:	drivers/pci/controller/pcie-rzg3s-host.c
+
 PCIE DRIVER FOR ROCKCHIP
 M:	Shawn Lin <shawn.lin@rock-chips.com>
 L:	linux-pci@vger.kernel.org
diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 0d98d8dd448b..f0befe29110a 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -296,6 +296,15 @@ config PCIE_HISI_ERR
 	  Say Y here if you want error handling support
 	  for the PCIe controller's errors on HiSilicon HIP SoCs
 
+config PCIE_RENESAS_RZG3S_HOST
+	bool "Renesas RZ/G3S PCIe host controller"
+	depends on ARCH_RENESAS || COMPILE_TEST
+	select MFD_SYSCON
+	select IRQ_MSI_LIB
+	help
+	  Say Y here if you want PCIe host controller support on Renesas RZ/G3S
+	  SoC.
+
 source "drivers/pci/controller/dwc/Kconfig"
 source "drivers/pci/controller/mobiveil/Kconfig"
 source "drivers/pci/controller/cadence/Kconfig"
diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
index 04c6edc285c5..0fcaaef0e7f0 100644
--- a/drivers/pci/controller/Makefile
+++ b/drivers/pci/controller/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
 obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
 obj-$(CONFIG_PCIE_RCAR_HOST) += pcie-rcar.o pcie-rcar-host.o
 obj-$(CONFIG_PCIE_RCAR_EP) += pcie-rcar.o pcie-rcar-ep.o
+obj-$(CONFIG_PCIE_RENESAS_RZG3S_HOST) += pcie-rzg3s-host.o
 obj-$(CONFIG_PCI_HOST_COMMON) += pci-host-common.o
 obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o
 obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o
diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c
new file mode 100644
index 000000000000..124c07d72ff6
--- /dev/null
+++ b/drivers/pci/controller/pcie-rzg3s-host.c
@@ -0,0 +1,1801 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PCIe driver for Renesas RZ/G3S SoCs
+ *
+ * Copyright (C) 2025 Renesas Electronics Corp.
+ *
+ * Based on:
+ *  drivers/pci/controller/pcie-rcar-host.c
+ *  Copyright (C) 2009 - 2011  Paul Mundt
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mutex.h>
+#include <linux/msi.h>
+#include <linux/of_irq.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/units.h>
+
+#include "../pci.h"
+
+/* AXI registers */
+#define RZG3S_PCI_REQDATA(id)			(0x80 + (id) * 0x4)
+#define RZG3S_PCI_REQRCVDAT			0x8c
+
+#define RZG3S_PCI_REQADR1			0x90
+#define RZG3S_PCI_REQADR1_BUS			GENMASK(31, 24)
+#define RZG3S_PCI_REQADR1_DEV			GENMASK(23, 19)
+#define RZG3S_PCI_REQADR1_FUNC			GENMASK(18, 16)
+#define RZG3S_PCI_REQADR1_REG			GENMASK(11, 0)
+
+#define RZG3S_PCI_REQBE				0x98
+#define RZG3S_PCI_REQBE_BYTE_EN			GENMASK(3, 0)
+
+#define RZG3S_PCI_REQISS			0x9c
+#define RZG3S_PCI_REQISS_MOR_STATUS		GENMASK(18, 16)
+#define RZG3S_PCI_REQISS_TR_TYPE		GENMASK(11, 8)
+#define RZG3S_PCI_REQISS_TR_TP0_RD		FIELD_PREP(RZG3S_PCI_REQISS_TR_TYPE, 0x4)
+#define RZG3S_PCI_REQISS_TR_TP0_WR		FIELD_PREP(RZG3S_PCI_REQISS_TR_TYPE, 0x5)
+#define RZG3S_PCI_REQISS_TR_TP1_RD		FIELD_PREP(RZG3S_PCI_REQISS_TR_TYPE, 0x6)
+#define RZG3S_PCI_REQISS_TR_TP1_WR		FIELD_PREP(RZG3S_PCI_REQISS_TR_TYPE, 0x7)
+#define RZG3S_PCI_REQISS_REQ_ISSUE		BIT(0)
+
+#define RZG3S_PCI_MSIRCVWADRL			0x100
+#define RZG3S_PCI_MSIRCVWADRL_MASK		GENMASK(31, 3)
+#define RZG3S_PCI_MSIRCVWADRL_MSG_DATA_ENA	BIT(1)
+#define RZG3S_PCI_MSIRCVWADRL_ENA		BIT(0)
+
+#define RZG3S_PCI_MSIRCVWADRU			0x104
+
+#define RZG3S_PCI_MSIRCVWMSKL			0x108
+#define RZG3S_PCI_MSIRCVWMSKL_MASK		GENMASK(31, 2)
+
+#define RZG3S_PCI_PINTRCVIE			0x110
+#define RZG3S_PCI_PINTRCVIE_INTX(i)		BIT(i)
+#define RZG3S_PCI_PINTRCVIE_MSI			BIT(4)
+
+#define RZG3S_PCI_PINTRCVIS			0x114
+#define RZG3S_PCI_PINTRCVIS_INTX(i)		BIT(i)
+#define RZG3S_PCI_PINTRCVIS_MSI			BIT(4)
+
+#define RZG3S_PCI_MSGRCVIE			0x120
+#define RZG3S_PCI_MSGRCVIE_MSG_RCV		BIT(24)
+
+#define RZG3S_PCI_MSGRCVIS			0x124
+#define RZG3S_PCI_MSGRCVIS_MRI			BIT(24)
+
+#define RZG3S_PCI_PEIE0				0x200
+
+#define RZG3S_PCI_PEIS0				0x204
+#define RZG3S_PCI_PEIS0_RX_DLLP_PM_ENTER	BIT(12)
+#define RZG3S_PCI_PEIS0_DL_UPDOWN		BIT(9)
+
+#define RZG3S_PCI_PEIE1				0x208
+#define RZG3S_PCI_PEIS1				0x20c
+#define RZG3S_PCI_AMEIS				0x214
+#define RZG3S_PCI_ASEIS1			0x224
+
+#define RZG3S_PCI_PCSTAT1			0x408
+#define RZG3S_PCI_PCSTAT1_LTSSM_STATE		GENMASK(14, 10)
+#define RZG3S_PCI_PCSTAT1_DL_DOWN_STS		BIT(0)
+
+#define RZG3S_PCI_PCCTRL2			0x410
+#define RZG3S_PCI_PCCTRL2_LS_CHG		GENMASK(9, 8)
+#define RZG3S_PCI_PCCTRL2_LS_CHG_REQ		BIT(0)
+
+#define RZG3S_PCI_PCSTAT2			0x414
+#define RZG3S_PCI_PCSTAT2_LS_CHG_DONE		BIT(28)
+#define RZG3S_PCI_PCSTAT2_SDRIRE		GENMASK(7, 1)
+
+#define RZG3S_PCI_PERM				0x300
+#define RZG3S_PCI_PERM_CFG_HWINIT_EN		BIT(2)
+#define RZG3S_PCI_PERM_PIPE_PHY_REG_EN		BIT(1)
+
+#define RZG3S_PCI_MSIRE(id)			(0x600 + (id) * 0x10)
+#define RZG3S_PCI_MSIRE_ENA			BIT(0)
+
+#define RZG3S_PCI_MSIRM(id)			(0x608 + (id) * 0x10)
+#define RZG3S_PCI_MSIRS(id)			(0x60c + (id) * 0x10)
+
+#define RZG3S_PCI_AWBASEL(id)			(0x1000 + (id) * 0x20)
+#define RZG3S_PCI_AWBASEL_WIN_ENA		BIT(0)
+
+#define RZG3S_PCI_AWBASEU(id)			(0x1004 + (id) * 0x20)
+#define RZG3S_PCI_AWMASKL(id)			(0x1008 + (id) * 0x20)
+#define RZG3S_PCI_AWMASKU(id)			(0x100c + (id) * 0x20)
+#define RZG3S_PCI_ADESTL(id)			(0x1010 + (id) * 0x20)
+#define RZG3S_PCI_ADESTU(id)			(0x1014 + (id) * 0x20)
+
+#define RZG3S_PCI_PWBASEL(id)			(0x1100 + (id) * 0x20)
+#define RZG3S_PCI_PWBASEL_ENA			BIT(0)
+
+#define RZG3S_PCI_PWBASEU(id)			(0x1104 + (id) * 0x20)
+#define RZG3S_PCI_PDESTL(id)			(0x1110 + (id) * 0x20)
+#define RZG3S_PCI_PDESTU(id)			(0x1114 + (id) * 0x20)
+#define RZG3S_PCI_PWMASKL(id)			(0x1108 + (id) * 0x20)
+#define RZG3S_PCI_PWMASKU(id)			(0x110c + (id) * 0x20)
+
+/* PHY control registers */
+#define RZG3S_PCI_PHY_XCFGD(id)			(0x2000 + (id) * 0x10)
+#define RZG3S_PCI_PHY_XCFGD_NUM			39
+
+#define RZG3S_PCI_PHY_XCFGA_CMN(id)		(0x2400 + (id) * 0x10)
+#define RZG3S_PCI_PHY_XCFGA_CMN_NUM		16
+
+#define RZG3S_PCI_PHY_XCFGA_RX(id)		(0x2500 + (id) * 0x10)
+#define RZG3S_PCI_PHY_XCFGA_RX_NUM		13
+
+#define RZG3S_PCI_PHY_XCFGA_TX			0x25d0
+
+#define RZG3S_PCI_PHY_XCFG_CTRL			0x2a20
+#define RZG3S_PCI_PHY_XCFG_CTRL_PHYREG_SEL	BIT(0)
+
+/* PCIe registers */
+#define RZG3S_PCI_CFG_BASE			0x6000
+#define RZG3S_PCI_CFG_BARMSK00L			0xa0
+#define RZG3S_PCI_CFG_BARMSK00U			0xa4
+
+#define RZG3S_PCI_CFG_PCIEC			0x60
+
+/* System controller registers */
+#define RZG3S_SYS_PCIE_RST_RSM_B		0xd74
+#define RZG3S_SYS_PCIE_RST_RSM_B_MASK		BIT(0)
+
+/* Maximum number of windows */
+#define RZG3S_MAX_WINDOWS			8
+
+/* Number of MSI interrupts per register */
+#define RZG3S_PCI_MSI_INT_PER_REG		32
+/* The number of MSI interrupts */
+#define RZG3S_PCI_MSI_INT_NR			RZG3S_PCI_MSI_INT_PER_REG
+
+/* Timeouts experimentally determined */
+#define RZG3S_REQ_ISSUE_TIMEOUT_US		2500
+
+/**
+ * struct rzg3s_pcie_msi - RZ/G3S PCIe MSI data structure
+ * @domain: IRQ domain
+ * @map: bitmap with the allocated MSIs
+ * @dma_addr: address of the allocated MSI window
+ * @window_base: base address of the MSI window
+ * @pages: allocated pages for MSI window mapping
+ * @map_lock: lock for bitmap with the allocated MSIs
+ * @irq: MSI interrupt
+ */
+struct rzg3s_pcie_msi {
+	struct irq_domain *domain;
+	DECLARE_BITMAP(map, RZG3S_PCI_MSI_INT_NR);
+	dma_addr_t dma_addr;
+	dma_addr_t window_base;
+	unsigned long pages;
+	struct mutex map_lock;
+	int irq;
+};
+
+struct rzg3s_pcie_host;
+
+/**
+ * struct rzg3s_pcie_soc_data - SoC specific data
+ * @init_phy: PHY initialization function
+ * @power_resets: array with the resets that need to be de-asserted after
+ *                power-on
+ * @cfg_resets: array with the resets that need to be de-asserted after
+ *              configuration
+ * @num_power_resets: number of power resets
+ * @num_cfg_resets: number of configuration resets
+ */
+struct rzg3s_pcie_soc_data {
+	int (*init_phy)(struct rzg3s_pcie_host *host);
+	const char * const *power_resets;
+	const char * const *cfg_resets;
+	u8 num_power_resets;
+	u8 num_cfg_resets;
+};
+
+/**
+ * struct rzg3s_pcie_port - RZ/G3S PCIe Root Port data structure
+ * @refclk: PCIe reference clock
+ * @vendor_id: Vendor ID
+ * @device_id: Device ID
+ */
+struct rzg3s_pcie_port {
+	struct clk *refclk;
+	u32 vendor_id;
+	u32 device_id;
+};
+
+/**
+ * struct rzg3s_pcie_host - RZ/G3S PCIe data structure
+ * @axi: base address for AXI registers
+ * @pcie: base address for PCIe registers
+ * @dev: struct device
+ * @power_resets: reset control signals that should be set after power up
+ * @cfg_resets: reset control signals that should be set after configuration
+ * @sysc: SYSC regmap
+ * @intx_domain: INTx IRQ domain
+ * @data: SoC specific data
+ * @msi: MSI data structure
+ * @port: PCIe Root Port
+ * @hw_lock: lock for access to the HW resources
+ * @intx_irqs: INTx interrupts
+ * @max_link_speed: maximum supported link speed
+ */
+struct rzg3s_pcie_host {
+	void __iomem *axi;
+	void __iomem *pcie;
+	struct device *dev;
+	struct reset_control_bulk_data *power_resets;
+	struct reset_control_bulk_data *cfg_resets;
+	struct regmap *sysc;
+	struct irq_domain *intx_domain;
+	const struct rzg3s_pcie_soc_data *data;
+	struct rzg3s_pcie_msi msi;
+	struct rzg3s_pcie_port port;
+	raw_spinlock_t hw_lock;
+	int intx_irqs[PCI_NUM_INTX];
+	int max_link_speed;
+};
+
+#define rzg3s_msi_to_host(_msi)	container_of(_msi, struct rzg3s_pcie_host, msi)
+
+static void rzg3s_pcie_update_bits(void __iomem *base, u32 offset, u32 mask,
+				   u32 val)
+{
+	u32 tmp;
+
+	tmp = readl_relaxed(base + offset);
+	tmp &= ~mask;
+	tmp |= val & mask;
+	writel_relaxed(tmp, base + offset);
+}
+
+static int rzg3s_pcie_child_issue_request(struct rzg3s_pcie_host *host)
+{
+	u32 val;
+	int ret;
+
+	rzg3s_pcie_update_bits(host->axi, RZG3S_PCI_REQISS,
+			       RZG3S_PCI_REQISS_REQ_ISSUE,
+			       RZG3S_PCI_REQISS_REQ_ISSUE);
+	ret = readl_poll_timeout_atomic(host->axi + RZG3S_PCI_REQISS, val,
+					!(val & RZG3S_PCI_REQISS_REQ_ISSUE),
+					5, RZG3S_REQ_ISSUE_TIMEOUT_US);
+
+	if (val & RZG3S_PCI_REQISS_MOR_STATUS)
+		return -EIO;
+
+	return ret;
+}
+
+static void rzg3s_pcie_child_prepare_bus(struct pci_bus *bus,
+					 unsigned int devfn, int where)
+{
+	struct rzg3s_pcie_host *host = bus->sysdata;
+	unsigned int dev, func, reg;
+
+	dev = PCI_SLOT(devfn);
+	func = PCI_FUNC(devfn);
+	reg = where & ~0x3;
+
+	/* Set the destination */
+	writel_relaxed(FIELD_PREP(RZG3S_PCI_REQADR1_BUS, bus->number) |
+		       FIELD_PREP(RZG3S_PCI_REQADR1_DEV, dev) |
+		       FIELD_PREP(RZG3S_PCI_REQADR1_FUNC, func) |
+		       FIELD_PREP(RZG3S_PCI_REQADR1_REG, reg),
+		       host->axi + RZG3S_PCI_REQADR1);
+
+	/* Set byte enable */
+	writel_relaxed(RZG3S_PCI_REQBE_BYTE_EN, host->axi + RZG3S_PCI_REQBE);
+}
+
+static int rzg3s_pcie_child_read_conf(struct rzg3s_pcie_host *host,
+				      struct pci_bus *bus, unsigned int devfn,
+				      int where, u32 *data)
+{
+	bool type0 = pci_is_root_bus(bus->parent) ? true : false;
+	int ret;
+
+	rzg3s_pcie_child_prepare_bus(bus, devfn, where);
+
+	/* Set the type of request */
+	writel_relaxed(type0 ? RZG3S_PCI_REQISS_TR_TP0_RD :
+			       RZG3S_PCI_REQISS_TR_TP1_RD,
+		       host->axi + RZG3S_PCI_REQISS);
+
+	/* Issue the request and wait to finish */
+	ret = rzg3s_pcie_child_issue_request(host);
+	if (ret)
+		return PCIBIOS_SET_FAILED;
+
+	/* Read the data */
+	*data = readl_relaxed(host->axi + RZG3S_PCI_REQRCVDAT);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+/* Serialization is provided by 'pci_lock' in drivers/pci/access.c */
+static int rzg3s_pcie_child_read(struct pci_bus *bus, unsigned int devfn,
+				 int where, int size, u32 *val)
+{
+	struct rzg3s_pcie_host *host = bus->sysdata;
+	int ret;
+
+	ret = rzg3s_pcie_child_read_conf(host, bus, devfn, where, val);
+	if (ret != PCIBIOS_SUCCESSFUL)
+		return ret;
+
+	if (size <= 2)
+		*val = (*val >> (8 * (where & 3))) & ((1 << (size * 8)) - 1);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int rzg3s_pcie_child_write_conf(struct rzg3s_pcie_host *host,
+				       struct pci_bus *bus, unsigned int devfn,
+				       int where, u32 data)
+{
+	bool type0 = pci_is_root_bus(bus->parent) ? true : false;
+	int ret;
+
+	rzg3s_pcie_child_prepare_bus(bus, devfn, where);
+
+	/* Set the write data */
+	writel_relaxed(0, host->axi + RZG3S_PCI_REQDATA(0));
+	writel_relaxed(0, host->axi + RZG3S_PCI_REQDATA(1));
+	writel_relaxed(data, host->axi + RZG3S_PCI_REQDATA(2));
+
+	/* Set the type of request */
+	writel_relaxed(type0 ? RZG3S_PCI_REQISS_TR_TP0_WR :
+			       RZG3S_PCI_REQISS_TR_TP1_WR,
+		       host->axi + RZG3S_PCI_REQISS);
+
+	/* Issue the request and wait to finish */
+	ret = rzg3s_pcie_child_issue_request(host);
+	if (ret)
+		return PCIBIOS_SET_FAILED;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+/* Serialization is provided by 'pci_lock' in drivers/pci/access.c */
+static int rzg3s_pcie_child_write(struct pci_bus *bus, unsigned int devfn,
+				  int where, int size, u32 val)
+{
+	struct rzg3s_pcie_host *host = bus->sysdata;
+	u32 data, shift;
+	int ret;
+
+	if (size == 4)
+		return rzg3s_pcie_child_write_conf(host, bus, devfn, where, val);
+
+	/*
+	 * Controller does 32 bit accesses. To do byte accesses software need
+	 * to do read/modify/write. This may have potential side effects. For
+	 * example, software may perform a 16-bit write. If the hardware only
+	 * supports 32-bit accesses, we must do a 32-bit read, merge in the 16
+	 * bits we intend to write, followed by a 32-bit write. If the 16 bits
+	 * we *don't* intend to write happen to have any RW1C
+	 * (write-one-to-clear) bits set, we just inadvertently cleared
+	 * something we shouldn't have.
+	 */
+	if (!bus->unsafe_warn) {
+		dev_warn(&bus->dev, "%d-byte config write to %04x:%02x:%02x.%d offset %#x may corrupt adjacent RW1C bits\n",
+			 size, pci_domain_nr(bus), bus->number,
+			 PCI_SLOT(devfn), PCI_FUNC(devfn), where);
+		bus->unsafe_warn = 1;
+	}
+
+	ret = rzg3s_pcie_child_read_conf(host, bus, devfn, where, &data);
+	if (ret != PCIBIOS_SUCCESSFUL)
+		return ret;
+
+	if (size == 1) {
+		shift = BITS_PER_BYTE * (where & 3);
+		data &= ~(0xff << shift);
+		data |= ((val & 0xff) << shift);
+	} else if (size == 2) {
+		shift = BITS_PER_BYTE * (where & 2);
+		data &= ~(0xffff << shift);
+		data |= ((val & 0xffff) << shift);
+	} else {
+		data = val;
+	}
+
+	return rzg3s_pcie_child_write_conf(host, bus, devfn, where, data);
+}
+
+static struct pci_ops rzg3s_pcie_child_ops = {
+	.read		= rzg3s_pcie_child_read,
+	.write		= rzg3s_pcie_child_write,
+};
+
+static void __iomem *rzg3s_pcie_root_map_bus(struct pci_bus *bus,
+					     unsigned int devfn, int where)
+{
+	struct rzg3s_pcie_host *host = bus->sysdata;
+
+	if (devfn)
+		return NULL;
+
+	return host->pcie + where;
+}
+
+/* Serialized by 'pci_lock' */
+static int rzg3s_pcie_root_write(struct pci_bus *bus, unsigned int devfn,
+				 int where, int size, u32 val)
+{
+	struct rzg3s_pcie_host *host = bus->sysdata;
+	int ret;
+
+	/* Enable access control to the CFGU */
+	writel_relaxed(RZG3S_PCI_PERM_CFG_HWINIT_EN,
+		       host->axi + RZG3S_PCI_PERM);
+
+	ret = pci_generic_config_write(bus, devfn, where, size, val);
+
+	/* Disable access control to the CFGU */
+	writel_relaxed(0, host->axi + RZG3S_PCI_PERM);
+
+	return ret;
+}
+
+static struct pci_ops rzg3s_pcie_root_ops = {
+	.read		= pci_generic_config_read,
+	.write		= rzg3s_pcie_root_write,
+	.map_bus	= rzg3s_pcie_root_map_bus,
+};
+
+static void rzg3s_pcie_intx_irq_handler(struct irq_desc *desc)
+{
+	struct rzg3s_pcie_host *host = irq_desc_get_handler_data(desc);
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	unsigned int irq = irq_desc_get_irq(desc);
+	u32 intx = irq - host->intx_irqs[0];
+	unsigned int intx_irq;
+
+	chained_irq_enter(chip, desc);
+	intx_irq = irq_find_mapping(host->intx_domain, intx);
+	if (intx_irq)
+		generic_handle_irq(intx_irq);
+	chained_irq_exit(chip, desc);
+}
+
+static irqreturn_t rzg3s_pcie_msi_irq(int irq, void *data)
+{
+	u8 regs = RZG3S_PCI_MSI_INT_NR / RZG3S_PCI_MSI_INT_PER_REG;
+	DECLARE_BITMAP(bitmap, RZG3S_PCI_MSI_INT_NR);
+	struct rzg3s_pcie_host *host = data;
+	struct rzg3s_pcie_msi *msi = &host->msi;
+	unsigned long bit;
+	u32 status;
+	u8 reg_id;
+
+	status = readl_relaxed(host->axi + RZG3S_PCI_PINTRCVIS);
+	if (!(status & RZG3S_PCI_PINTRCVIS_MSI))
+		return IRQ_NONE;
+
+	/* Clear the MSI */
+	rzg3s_pcie_update_bits(host->axi, RZG3S_PCI_PINTRCVIS,
+			       RZG3S_PCI_PINTRCVIS_MSI,
+			       RZG3S_PCI_PINTRCVIS_MSI);
+	rzg3s_pcie_update_bits(host->axi, RZG3S_PCI_MSGRCVIS,
+			       RZG3S_PCI_MSGRCVIS_MRI, RZG3S_PCI_MSGRCVIS_MRI);
+
+	for (reg_id = 0; reg_id < regs; reg_id++) {
+		status = readl_relaxed(host->axi + RZG3S_PCI_MSIRS(reg_id));
+		bitmap_write(bitmap, status, reg_id * RZG3S_PCI_MSI_INT_PER_REG,
+			     RZG3S_PCI_MSI_INT_PER_REG);
+	}
+
+	for_each_set_bit(bit, bitmap, RZG3S_PCI_MSI_INT_NR) {
+		unsigned int msi_irq;
+
+		msi_irq = irq_find_mapping(msi->domain->parent, bit);
+		if (msi_irq && test_bit(bit, msi->map)) {
+			generic_handle_irq(msi_irq);
+		} else {
+			u8 reg_bit = bit % RZG3S_PCI_MSI_INT_PER_REG;
+			u8 reg_id = bit / RZG3S_PCI_MSI_INT_PER_REG;
+
+			/* Unknown MSI, just clear it */
+			writel_relaxed(BIT(reg_bit),
+				       host->axi + RZG3S_PCI_MSIRS(reg_id));
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void rzg3s_pcie_msi_top_irq_ack(struct irq_data *d)
+{
+	irq_chip_ack_parent(d);
+}
+
+static void rzg3s_pcie_msi_top_irq_mask(struct irq_data *d)
+{
+	pci_msi_mask_irq(d);
+	irq_chip_mask_parent(d);
+}
+
+static void rzg3s_pcie_msi_top_irq_unmask(struct irq_data *d)
+{
+	pci_msi_unmask_irq(d);
+	irq_chip_unmask_parent(d);
+}
+
+static struct irq_chip rzg3s_pcie_msi_top_chip = {
+	.name		= "PCIe MSI",
+	.irq_ack	= rzg3s_pcie_msi_top_irq_ack,
+	.irq_mask	= rzg3s_pcie_msi_top_irq_mask,
+	.irq_unmask	= rzg3s_pcie_msi_top_irq_unmask,
+};
+
+static void rzg3s_pcie_msi_irq_ack(struct irq_data *d)
+{
+	struct rzg3s_pcie_msi *msi = irq_data_get_irq_chip_data(d);
+	struct rzg3s_pcie_host *host = rzg3s_msi_to_host(msi);
+	u8 reg_bit = d->hwirq % RZG3S_PCI_MSI_INT_PER_REG;
+	u8 reg_id = d->hwirq / RZG3S_PCI_MSI_INT_PER_REG;
+
+	guard(raw_spinlock_irqsave)(&host->hw_lock);
+
+	writel_relaxed(BIT(reg_bit), host->axi + RZG3S_PCI_MSIRS(reg_id));
+}
+
+static void rzg3s_pcie_msi_irq_mask(struct irq_data *d)
+{
+	struct rzg3s_pcie_msi *msi = irq_data_get_irq_chip_data(d);
+	struct rzg3s_pcie_host *host = rzg3s_msi_to_host(msi);
+	u8 reg_bit = d->hwirq % RZG3S_PCI_MSI_INT_PER_REG;
+	u8 reg_id = d->hwirq / RZG3S_PCI_MSI_INT_PER_REG;
+
+	guard(raw_spinlock_irqsave)(&host->hw_lock);
+
+	rzg3s_pcie_update_bits(host->axi, RZG3S_PCI_MSIRM(reg_id), BIT(reg_bit),
+			       BIT(reg_bit));
+}
+
+static void rzg3s_pcie_msi_irq_unmask(struct irq_data *d)
+{
+	struct rzg3s_pcie_msi *msi = irq_data_get_irq_chip_data(d);
+	struct rzg3s_pcie_host *host = rzg3s_msi_to_host(msi);
+	u8 reg_bit = d->hwirq % RZG3S_PCI_MSI_INT_PER_REG;
+	u8 reg_id = d->hwirq / RZG3S_PCI_MSI_INT_PER_REG;
+
+	guard(raw_spinlock_irqsave)(&host->hw_lock);
+
+	rzg3s_pcie_update_bits(host->axi, RZG3S_PCI_MSIRM(reg_id), BIT(reg_bit),
+			       0);
+}
+
+static void rzg3s_pcie_irq_compose_msi_msg(struct irq_data *data,
+					   struct msi_msg *msg)
+{
+	struct rzg3s_pcie_msi *msi = irq_data_get_irq_chip_data(data);
+	struct rzg3s_pcie_host *host = rzg3s_msi_to_host(msi);
+	u32 lo, hi;
+
+	/*
+	 * Enable and msg data enable bits are part of the address lo. Drop
+	 * them along with the unused bit.
+	 */
+	lo = readl_relaxed(host->axi + RZG3S_PCI_MSIRCVWADRL) &
+	     RZG3S_PCI_MSIRCVWADRL_MASK;
+	hi = readl_relaxed(host->axi + RZG3S_PCI_MSIRCVWADRU);
+
+	msg->address_lo = lo;
+	msg->address_hi = hi;
+	msg->data = data->hwirq;
+}
+
+static struct irq_chip rzg3s_pcie_msi_bottom_chip = {
+	.name			= "rzg3s-pcie-msi",
+	.irq_ack		= rzg3s_pcie_msi_irq_ack,
+	.irq_mask		= rzg3s_pcie_msi_irq_mask,
+	.irq_unmask		= rzg3s_pcie_msi_irq_unmask,
+	.irq_compose_msi_msg	= rzg3s_pcie_irq_compose_msi_msg,
+};
+
+static int rzg3s_pcie_msi_domain_alloc(struct irq_domain *domain,
+				       unsigned int virq, unsigned int nr_irqs,
+				       void *args)
+{
+	struct rzg3s_pcie_msi *msi = domain->host_data;
+	unsigned int i;
+	int hwirq;
+
+	mutex_lock(&msi->map_lock);
+	hwirq = bitmap_find_free_region(msi->map, RZG3S_PCI_MSI_INT_NR,
+					order_base_2(nr_irqs));
+	mutex_unlock(&msi->map_lock);
+
+	if (hwirq < 0)
+		return -ENOSPC;
+
+	for (i = 0; i < nr_irqs; i++) {
+		irq_domain_set_info(domain, virq + i, hwirq + i,
+				    &rzg3s_pcie_msi_bottom_chip,
+				    domain->host_data, handle_edge_irq, NULL,
+				    NULL);
+	}
+
+	return 0;
+}
+
+static void rzg3s_pcie_msi_domain_free(struct irq_domain *domain,
+				       unsigned int virq, unsigned int nr_irqs)
+{
+	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
+	struct rzg3s_pcie_msi *msi = domain->host_data;
+
+	guard(mutex)(&msi->map_lock);
+
+	bitmap_release_region(msi->map, d->hwirq, order_base_2(nr_irqs));
+}
+
+static const struct irq_domain_ops rzg3s_pcie_msi_domain_ops = {
+	.alloc	= rzg3s_pcie_msi_domain_alloc,
+	.free	= rzg3s_pcie_msi_domain_free,
+};
+
+static struct msi_domain_info rzg3s_pcie_msi_info = {
+	.flags	= MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+		  MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_NO_AFFINITY,
+	.chip	= &rzg3s_pcie_msi_top_chip,
+};
+
+static int rzg3s_pcie_msi_allocate_domains(struct rzg3s_pcie_msi *msi)
+{
+	struct rzg3s_pcie_host *host = rzg3s_msi_to_host(msi);
+	struct device *dev = host->dev;
+	struct fwnode_handle *fwnode = dev_fwnode(dev);
+	struct irq_domain *parent;
+
+	parent = irq_domain_create_linear(fwnode, RZG3S_PCI_MSI_INT_NR,
+					  &rzg3s_pcie_msi_domain_ops, msi);
+	if (!parent)
+		return dev_err_probe(dev, -ENOMEM,
+				     "failed to create IRQ domain\n");
+	irq_domain_update_bus_token(parent, DOMAIN_BUS_NEXUS);
+
+	msi->domain = pci_msi_create_irq_domain(fwnode, &rzg3s_pcie_msi_info,
+						parent);
+	if (!msi->domain) {
+		irq_domain_remove(parent);
+		return dev_err_probe(dev, -ENOMEM,
+				     "failed to create IRQ domain\n");
+	}
+
+	return 0;
+}
+
+static int rzg3s_pcie_msi_hw_setup(struct rzg3s_pcie_host *host)
+{
+	u8 regs = RZG3S_PCI_MSI_INT_NR / RZG3S_PCI_MSI_INT_PER_REG;
+	struct rzg3s_pcie_msi *msi = &host->msi;
+	u8 reg_id;
+
+	/*
+	 * Set MSI window size. HW will set the window to
+	 * RZG3S_PCI_MSI_INT_NR * 4 bytes.
+	 */
+	writel_relaxed(FIELD_PREP(RZG3S_PCI_MSIRCVWMSKL_MASK,
+				  RZG3S_PCI_MSI_INT_NR - 1),
+		       host->axi + RZG3S_PCI_MSIRCVWMSKL);
+
+	/* Set MSI window address and enable MSI window */
+	writel_relaxed(upper_32_bits(msi->window_base),
+		       host->axi + RZG3S_PCI_MSIRCVWADRU);
+	writel_relaxed(lower_32_bits(msi->window_base) |
+		       RZG3S_PCI_MSIRCVWADRL_ENA |
+		       RZG3S_PCI_MSIRCVWADRL_MSG_DATA_ENA,
+		       host->axi + RZG3S_PCI_MSIRCVWADRL);
+
+	/* Set MSI receive enable */
+	for (reg_id = 0; reg_id < regs; reg_id++) {
+		writel_relaxed(RZG3S_PCI_MSIRE_ENA,
+			       host->axi + RZG3S_PCI_MSIRE(reg_id));
+	}
+
+	/* Enable message receive interrupts */
+	writel_relaxed(RZG3S_PCI_MSGRCVIE_MSG_RCV,
+		       host->axi + RZG3S_PCI_MSGRCVIE);
+
+	/* Enable MSI */
+	rzg3s_pcie_update_bits(host->axi, RZG3S_PCI_PINTRCVIE,
+			       RZG3S_PCI_PINTRCVIE_MSI,
+			       RZG3S_PCI_PINTRCVIE_MSI);
+
+	return 0;
+}
+
+static int rzg3s_pcie_msi_setup(struct rzg3s_pcie_host *host)
+{
+	size_t size = RZG3S_PCI_MSI_INT_NR * sizeof(u32);
+	struct rzg3s_pcie_msi *msi = &host->msi;
+	struct device *dev = host->dev;
+	int id, ret;
+
+	msi->pages = __get_free_pages(GFP_KERNEL | GFP_DMA, 0);
+	if (!msi->pages)
+		return -ENOMEM;
+
+	msi->dma_addr = dma_map_single(dev, (void *)msi->pages, size * 2,
+				       DMA_BIDIRECTIONAL);
+	if (dma_mapping_error(dev, msi->dma_addr)) {
+		ret = -ENOMEM;
+		goto free_pages;
+	}
+
+	/*
+	 * According to the RZ/G3S HW manual (Rev.1.10, section 34.4.5.2 Setting
+	 * the MSI Window) the MSI window needs to fall within one of the
+	 * enabled AXI windows. Find an enabled AXI window to setup the MSI
+	 * window.
+	 */
+	for (id = 0; id < RZG3S_MAX_WINDOWS; id++) {
+		u64 base, basel, baseu;
+		u64 mask, maskl, masku;
+
+		basel = readl_relaxed(host->axi + RZG3S_PCI_AWBASEL(id));
+		/* Skip checking this AXI window if it's not enabled */
+		if (!(basel & RZG3S_PCI_AWBASEL_WIN_ENA))
+			continue;
+
+		baseu = readl_relaxed(host->axi + RZG3S_PCI_AWBASEU(id));
+		base = baseu << 32 | basel;
+
+		maskl = readl_relaxed(host->axi + RZG3S_PCI_AWMASKL(id));
+		masku = readl_relaxed(host->axi + RZG3S_PCI_AWMASKU(id));
+		mask = masku << 32 | maskl;
+
+		if (msi->dma_addr < base || msi->dma_addr > base + mask)
+			continue;
+
+		break;
+	}
+
+	if (id == RZG3S_MAX_WINDOWS) {
+		ret = -EINVAL;
+		goto dma_unmap;
+	}
+
+	/* The MSI base address must be aligned to the MSI size */
+	msi->window_base = ALIGN(msi->dma_addr, size);
+	if (msi->window_base < msi->dma_addr) {
+		ret = -EINVAL;
+		goto dma_unmap;
+	}
+
+	rzg3s_pcie_msi_hw_setup(host);
+
+	return 0;
+
+dma_unmap:
+	dma_unmap_single(dev, msi->dma_addr, size * 2, DMA_BIDIRECTIONAL);
+free_pages:
+	free_pages(msi->pages, 0);
+	return ret;
+}
+
+static void rzg3s_pcie_msi_hw_teardown(struct rzg3s_pcie_host *host)
+{
+	u8 regs = RZG3S_PCI_MSI_INT_NR / RZG3S_PCI_MSI_INT_PER_REG;
+	u8 reg_id;
+
+	/* Disable MSI */
+	rzg3s_pcie_update_bits(host->axi, RZG3S_PCI_PINTRCVIE,
+			       RZG3S_PCI_PINTRCVIE_MSI, 0);
+
+	/* Disable message receive interrupts */
+	rzg3s_pcie_update_bits(host->axi, RZG3S_PCI_MSGRCVIE,
+			       RZG3S_PCI_MSGRCVIE_MSG_RCV, 0);
+
+	/* Disable MSI receive enable */
+	for (reg_id = 0; reg_id < regs; reg_id++)
+		writel_relaxed(0, host->axi + RZG3S_PCI_MSIRE(reg_id));
+
+	/* Disable MSI window */
+	writel_relaxed(0, host->axi + RZG3S_PCI_MSIRCVWADRL);
+}
+
+static void rzg3s_pcie_teardown_msi(struct rzg3s_pcie_host *host)
+{
+	size_t size = RZG3S_PCI_MSI_INT_NR * sizeof(u32);
+	struct rzg3s_pcie_msi *msi = &host->msi;
+	struct irq_domain *parent = msi->domain->parent;
+
+	rzg3s_pcie_msi_hw_teardown(host);
+
+	free_irq(msi->irq, host);
+	irq_domain_remove(msi->domain);
+	irq_domain_remove(parent);
+
+	/* Free unused memory */
+	dma_unmap_single(host->dev, msi->dma_addr, size * 2, DMA_BIDIRECTIONAL);
+	free_pages(msi->pages, 0);
+}
+
+static void rzg3s_pcie_msi_mutex_destroy(void *data)
+{
+	mutex_destroy(data);
+}
+
+static int rzg3s_pcie_init_msi(struct rzg3s_pcie_host *host)
+{
+	struct platform_device *pdev = to_platform_device(host->dev);
+	struct rzg3s_pcie_msi *msi = &host->msi;
+	struct device *dev = host->dev;
+	struct irq_domain *parent;
+	const char *devname;
+	int ret;
+
+	mutex_init(&msi->map_lock);
+	ret = devm_add_action_or_reset(dev, rzg3s_pcie_msi_mutex_destroy,
+				       &msi->map_lock);
+	if (ret)
+		return ret;
+
+	msi->irq = platform_get_irq_byname(pdev, "msi");
+	if (msi->irq < 0)
+		return dev_err_probe(dev, msi->irq, "Failed to get MSI IRQ!\n");
+
+	devname = devm_kasprintf(dev, GFP_KERNEL, "%s-msi", dev_name(dev));
+	if (!devname)
+		return -ENOMEM;
+
+	ret = rzg3s_pcie_msi_allocate_domains(msi);
+	if (ret)
+		return ret;
+
+	/*
+	 * Don't use devm_request_irq() as the driver uses non-devm helpers
+	 * to control clocks. Mixing them may lead to subtle bugs.
+	 */
+	ret = request_irq(msi->irq, rzg3s_pcie_msi_irq, 0, devname, host);
+	if (ret) {
+		dev_err_probe(dev, ret, "Failed to request IRQ: %d\n", ret);
+		goto free_domains;
+	}
+
+	ret = rzg3s_pcie_msi_setup(host);
+	if (ret) {
+		dev_err_probe(dev, ret, "Failed to setup MSI!\n");
+		goto free_irq;
+	}
+
+	return 0;
+
+free_irq:
+	free_irq(msi->irq, host);
+free_domains:
+	parent = msi->domain->parent;
+	irq_domain_remove(msi->domain);
+	irq_domain_remove(parent);
+	return ret;
+}
+
+static void rzg3s_pcie_intx_irq_ack(struct irq_data *d)
+{
+	struct rzg3s_pcie_host *host = irq_data_get_irq_chip_data(d);
+
+	guard(raw_spinlock_irqsave)(&host->hw_lock);
+
+	rzg3s_pcie_update_bits(host->axi, RZG3S_PCI_PINTRCVIS,
+			       RZG3S_PCI_PINTRCVIS_INTX(d->hwirq),
+			       RZG3S_PCI_PINTRCVIS_INTX(d->hwirq));
+}
+
+static void rzg3s_pcie_intx_irq_mask(struct irq_data *d)
+{
+	struct rzg3s_pcie_host *host = irq_data_get_irq_chip_data(d);
+
+	guard(raw_spinlock_irqsave)(&host->hw_lock);
+
+	rzg3s_pcie_update_bits(host->axi, RZG3S_PCI_PINTRCVIE,
+			       RZG3S_PCI_PINTRCVIE_INTX(d->hwirq), 0);
+}
+
+static void rzg3s_pcie_intx_irq_unmask(struct irq_data *d)
+{
+	struct rzg3s_pcie_host *host = irq_data_get_irq_chip_data(d);
+
+	guard(raw_spinlock_irqsave)(&host->hw_lock);
+
+	rzg3s_pcie_update_bits(host->axi, RZG3S_PCI_PINTRCVIE,
+			       RZG3S_PCI_PINTRCVIE_INTX(d->hwirq),
+			       RZG3S_PCI_PINTRCVIE_INTX(d->hwirq));
+}
+
+static struct irq_chip rzg3s_pcie_intx_irq_chip = {
+	.name = "PCIe INTx",
+	.irq_ack = rzg3s_pcie_intx_irq_ack,
+	.irq_mask = rzg3s_pcie_intx_irq_mask,
+	.irq_unmask = rzg3s_pcie_intx_irq_unmask,
+};
+
+static int rzg3s_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
+			       irq_hw_number_t hwirq)
+{
+	irq_set_chip_and_handler(irq, &rzg3s_pcie_intx_irq_chip,
+				 handle_level_irq);
+	irq_set_chip_data(irq, domain->host_data);
+
+	return 0;
+}
+
+static const struct irq_domain_ops rzg3s_pcie_intx_domain_ops = {
+	.map = rzg3s_pcie_intx_map,
+	.xlate = irq_domain_xlate_onetwocell,
+};
+
+static int rzg3s_pcie_init_irqdomain(struct rzg3s_pcie_host *host)
+{
+	struct device *dev = host->dev;
+	struct platform_device *pdev = to_platform_device(dev);
+	int i;
+
+	for (i = 0; i < PCI_NUM_INTX; i++) {
+		char irq_name[5] = {0};
+		int irq;
+
+		scnprintf(irq_name, ARRAY_SIZE(irq_name), "int%c", 'a' + i);
+
+		irq = platform_get_irq_byname(pdev, irq_name);
+		if (irq < 0)
+			return dev_err_probe(dev, -EINVAL,
+					     "Failed to parse and map INT%c IRQ\n",
+					     'A' + i);
+
+		host->intx_irqs[i] = irq;
+		irq_set_chained_handler_and_data(irq,
+						 rzg3s_pcie_intx_irq_handler,
+						 host);
+	}
+
+	host->intx_domain = irq_domain_create_linear(dev_fwnode(dev),
+						     PCI_NUM_INTX,
+						     &rzg3s_pcie_intx_domain_ops,
+						     host);
+	if (!host->intx_domain)
+		return dev_err_probe(dev, -EINVAL,
+				     "Failed to add irq domain for INTx IRQs\n");
+	irq_domain_update_bus_token(host->intx_domain, DOMAIN_BUS_WIRED);
+
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		int ret = rzg3s_pcie_init_msi(host);
+
+		if (ret) {
+			irq_domain_remove(host->intx_domain);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void rzg3s_pcie_teardown_irqdomain(struct rzg3s_pcie_host *host)
+{
+	if (IS_ENABLED(CONFIG_PCI_MSI))
+		rzg3s_pcie_teardown_msi(host);
+
+	irq_domain_remove(host->intx_domain);
+}
+
+static int rzg3s_pcie_set_max_link_speed(struct rzg3s_pcie_host *host)
+{
+	u32 remote_supported_link_speeds, max_supported_link_speeds;
+	u32 cs2, tmp, pcie_cap = RZG3S_PCI_CFG_PCIEC;
+	u32 cur_link_speed, link_speed;
+	u8 ltssm_state_l0 = 0xc;
+	int ret;
+	u16 ls;
+
+	/*
+	 * According to the RZ/G3S HW manual (Rev.1.10, section 34.6.3 Caution
+	 * when Changing the Speed Spontaneously) link speed change can be done
+	 * only when the LTSSM is in L0.
+	 */
+	ret = readl_poll_timeout(host->axi + RZG3S_PCI_PCSTAT1, tmp,
+				 FIELD_GET(RZG3S_PCI_PCSTAT1_LTSSM_STATE, tmp) == ltssm_state_l0,
+				 PCIE_LINK_WAIT_SLEEP_MS * MILLI,
+				 PCIE_LINK_WAIT_SLEEP_MS * MILLI *
+				 PCIE_LINK_WAIT_MAX_RETRIES);
+	if (ret)
+		return ret;
+
+	ls = readw_relaxed(host->pcie + pcie_cap + PCI_EXP_LNKSTA);
+	cs2 = readl_relaxed(host->axi + RZG3S_PCI_PCSTAT2);
+
+	switch (pcie_link_speed[host->max_link_speed]) {
+	case PCIE_SPEED_5_0GT:
+		max_supported_link_speeds = GENMASK(PCI_EXP_LNKSTA_CLS_5_0GB - 1, 0);
+		link_speed = PCI_EXP_LNKCTL2_TLS_5_0GT;
+		break;
+	default:
+		/* Should not happen */
+		return -EINVAL;
+	}
+
+	cur_link_speed = FIELD_GET(PCI_EXP_LNKSTA_CLS, ls);
+	remote_supported_link_speeds = FIELD_GET(RZG3S_PCI_PCSTAT2_SDRIRE, cs2);
+	/* Drop reserved bits */
+	remote_supported_link_speeds &= max_supported_link_speeds;
+
+	/*
+	 * Return if max link speed is already set or the connected device
+	 * doesn't support it.
+	 */
+	if (cur_link_speed == host->max_link_speed ||
+	    remote_supported_link_speeds != max_supported_link_speeds)
+		return 0;
+
+	/* Set target Link speed */
+	rzg3s_pcie_update_bits(host->pcie, pcie_cap + PCI_EXP_LNKCTL2,
+			       PCI_EXP_LNKCTL2_TLS,
+			       FIELD_PREP(PCI_EXP_LNKCTL2_TLS, link_speed));
+
+	/* Request link speed change */
+	rzg3s_pcie_update_bits(host->axi, RZG3S_PCI_PCCTRL2,
+			       RZG3S_PCI_PCCTRL2_LS_CHG_REQ |
+			       RZG3S_PCI_PCCTRL2_LS_CHG,
+			       RZG3S_PCI_PCCTRL2_LS_CHG_REQ |
+			       FIELD_PREP(RZG3S_PCI_PCCTRL2_LS_CHG,
+					  link_speed - 1));
+
+	ret = readl_poll_timeout(host->axi + RZG3S_PCI_PCSTAT2, cs2,
+				 (cs2 & RZG3S_PCI_PCSTAT2_LS_CHG_DONE),
+				 PCIE_LINK_WAIT_SLEEP_MS * MILLI,
+				 PCIE_LINK_WAIT_SLEEP_MS * MILLI *
+				 PCIE_LINK_WAIT_MAX_RETRIES);
+
+	/*
+	 * According to the RZ/G3S HW manual (Rev.1.10, section 34.6.3 Caution
+	 * when Changing the Speed Spontaneously) the PCI_PCCTRL2_LS_CHG_REQ
+	 * should be de-asserted after checking for PCI_PCSTAT2_LS_CHG_DONE.
+	 */
+	rzg3s_pcie_update_bits(host->axi, RZG3S_PCI_PCCTRL2,
+			       RZG3S_PCI_PCCTRL2_LS_CHG_REQ, 0);
+
+	return ret;
+}
+
+static int rzg3s_pcie_config_init(struct rzg3s_pcie_host *host)
+{
+	struct pci_host_bridge *bridge = pci_host_bridge_from_priv(host);
+	struct resource_entry *ft;
+	struct resource *bus;
+	u8 subordinate_bus;
+	u8 secondary_bus;
+	u8 primary_bus;
+
+	ft = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
+	if (!ft)
+		return -ENODEV;
+
+	bus = ft->res;
+	primary_bus = bus->start;
+	secondary_bus = bus->start + 1;
+	subordinate_bus = bus->end;
+
+	/* Enable access control to the CFGU */
+	writel_relaxed(RZG3S_PCI_PERM_CFG_HWINIT_EN,
+		       host->axi + RZG3S_PCI_PERM);
+
+	/* HW manual recommends to write 0xffffffff on initialization */
+	writel_relaxed(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00L);
+	writel_relaxed(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00U);
+
+	/* Update bus info */
+	writeb_relaxed(primary_bus, host->pcie + PCI_PRIMARY_BUS);
+	writeb_relaxed(secondary_bus, host->pcie + PCI_SECONDARY_BUS);
+	writeb_relaxed(subordinate_bus, host->pcie + PCI_SUBORDINATE_BUS);
+
+	/* Disable access control to the CFGU */
+	writel_relaxed(0, host->axi + RZG3S_PCI_PERM);
+
+	return 0;
+}
+
+static void rzg3s_pcie_irq_init(struct rzg3s_pcie_host *host)
+{
+	/*
+	 * According to the HW manual of the RZ/G3S (Rev.1.10, sections
+	 * corresponding to all registers written with ~0U), the hardware
+	 * ignores value written to unused bits. Writing ~0U to these registers
+	 * should be safe.
+	 */
+
+	/* Clear the link state and PM transitions */
+	writel_relaxed(RZG3S_PCI_PEIS0_DL_UPDOWN |
+		       RZG3S_PCI_PEIS0_RX_DLLP_PM_ENTER,
+		       host->axi + RZG3S_PCI_PEIS0);
+
+	/* Disable all interrupts */
+	writel_relaxed(0, host->axi + RZG3S_PCI_PEIE0);
+
+	/* Clear all parity and ecc error interrupts */
+	writel_relaxed(~0U, host->axi + RZG3S_PCI_PEIS1);
+
+	/* Disable all parity and ecc error interrupts */
+	writel_relaxed(0, host->axi + RZG3S_PCI_PEIE1);
+
+	/* Clear all AXI master error interrupts */
+	writel_relaxed(~0U, host->axi + RZG3S_PCI_AMEIS);
+
+	/* Clear all AXI slave error interrupts */
+	writel_relaxed(~0U, host->axi + RZG3S_PCI_ASEIS1);
+
+	/* Clear all message receive interrupts */
+	writel_relaxed(~0U, host->axi + RZG3S_PCI_MSGRCVIS);
+}
+
+static int rzg3s_pcie_power_resets_deassert(struct rzg3s_pcie_host *host)
+{
+	const struct rzg3s_pcie_soc_data *data = host->data;
+
+	/*
+	 * According to the RZ/G3S HW manual (Rev.1.10, section
+	 * 34.5.1.2 De-asserting the Reset) the PCIe IP needs to wait 5ms from
+	 * power on to the de-assertion of reset.
+	 */
+	fsleep(5000);
+	return reset_control_bulk_deassert(data->num_power_resets,
+					   host->power_resets);
+}
+
+static int rzg3s_pcie_resets_prepare_and_get(struct rzg3s_pcie_host *host)
+{
+	const struct rzg3s_pcie_soc_data *data = host->data;
+	unsigned int i;
+	int ret;
+
+	host->power_resets = devm_kmalloc_array(host->dev,
+						data->num_power_resets,
+						sizeof(*host->power_resets),
+						GFP_KERNEL);
+	if (!host->power_resets)
+		return -ENOMEM;
+
+	for (i = 0; i < data->num_power_resets; i++)
+		host->power_resets[i].id = data->power_resets[i];
+
+	host->cfg_resets = devm_kmalloc_array(host->dev,
+					      data->num_cfg_resets,
+					      sizeof(*host->cfg_resets),
+					      GFP_KERNEL);
+	if (!host->cfg_resets)
+		return -ENOMEM;
+
+	for (i = 0; i < data->num_cfg_resets; i++)
+		host->cfg_resets[i].id = data->cfg_resets[i];
+
+	ret = devm_reset_control_bulk_get_exclusive(host->dev,
+						    data->num_power_resets,
+						    host->power_resets);
+	if (ret)
+		return ret;
+
+	return devm_reset_control_bulk_get_exclusive(host->dev,
+						     data->num_cfg_resets,
+						     host->cfg_resets);
+}
+
+static int rzg3s_pcie_host_parse_port(struct rzg3s_pcie_host *host)
+{
+	struct device_node *of_port = of_get_next_child(host->dev->of_node, NULL);
+	struct rzg3s_pcie_port *port = &host->port;
+	int ret;
+
+	ret = of_property_read_u32(of_port, "vendor-id", &port->vendor_id);
+	if (ret)
+		return ret;
+
+	ret = of_property_read_u32(of_port, "device-id", &port->device_id);
+	if (ret)
+		return ret;
+
+	port->refclk = of_clk_get_by_name(of_port, "ref");
+	if (IS_ERR(port->refclk))
+		return PTR_ERR(port->refclk);
+
+	return 0;
+}
+
+static int rzg3s_pcie_host_init_port(struct rzg3s_pcie_host *host)
+{
+	struct rzg3s_pcie_port *port = &host->port;
+	struct device *dev = host->dev;
+	int ret;
+
+	/* Enable access control to the CFGU */
+	writel_relaxed(RZG3S_PCI_PERM_CFG_HWINIT_EN,
+		       host->axi + RZG3S_PCI_PERM);
+
+	/* Update vendor ID and device ID */
+	writew_relaxed(port->vendor_id, host->pcie + PCI_VENDOR_ID);
+	writew_relaxed(port->device_id, host->pcie + PCI_DEVICE_ID);
+
+	/* Disable access control to the CFGU */
+	writel_relaxed(0, host->axi + RZG3S_PCI_PERM);
+
+	ret = clk_prepare_enable(port->refclk);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to enable refclk!\n");
+
+	/* Set the PHY, if any */
+	if (host->data->init_phy) {
+		ret = host->data->init_phy(host);
+		if (ret) {
+			dev_err_probe(dev, ret, "Failed to set the PHY!\n");
+			goto refclk_disable;
+		}
+	}
+
+	return 0;
+
+refclk_disable:
+	clk_disable_unprepare(port->refclk);
+	return ret;
+}
+
+static int rzg3s_pcie_host_init(struct rzg3s_pcie_host *host)
+{
+	u32 val;
+	int ret;
+
+	/* Initialize the PCIe related registers */
+	ret = rzg3s_pcie_config_init(host);
+	if (ret)
+		return ret;
+
+	ret = rzg3s_pcie_host_init_port(host);
+	if (ret)
+		return ret;
+
+	/* Initialize the interrupts */
+	rzg3s_pcie_irq_init(host);
+
+	ret = reset_control_bulk_deassert(host->data->num_cfg_resets,
+					  host->cfg_resets);
+	if (ret)
+		goto disable_port_refclk;
+
+	/* Wait for link up */
+	ret = readl_poll_timeout(host->axi + RZG3S_PCI_PCSTAT1, val,
+				 !(val & RZG3S_PCI_PCSTAT1_DL_DOWN_STS),
+				 PCIE_LINK_WAIT_SLEEP_MS * MILLI,
+				 PCIE_LINK_WAIT_SLEEP_MS * MILLI *
+				 PCIE_LINK_WAIT_MAX_RETRIES);
+	if (ret)
+		goto cfg_resets_deassert;
+
+	val = readl_relaxed(host->axi + RZG3S_PCI_PCSTAT2);
+	dev_info(host->dev, "PCIe link status [0x%x]\n", val);
+
+	return 0;
+
+cfg_resets_deassert:
+	reset_control_bulk_assert(host->data->num_cfg_resets,
+				  host->cfg_resets);
+disable_port_refclk:
+	clk_disable_unprepare(host->port.refclk);
+	return ret;
+}
+
+static void rzg3s_pcie_set_inbound_window(struct rzg3s_pcie_host *host,
+					  u64 cpu_addr, u64 pci_addr, u64 size,
+					  int id)
+{
+	/* Set CPU window base address */
+	writel_relaxed(upper_32_bits(cpu_addr),
+		       host->axi + RZG3S_PCI_ADESTU(id));
+	writel_relaxed(lower_32_bits(cpu_addr),
+		       host->axi + RZG3S_PCI_ADESTL(id));
+
+	/* Set window size */
+	writel_relaxed(upper_32_bits(size), host->axi + RZG3S_PCI_AWMASKU(id));
+	writel_relaxed(lower_32_bits(size), host->axi + RZG3S_PCI_AWMASKL(id));
+
+	/* Set PCIe window base address and enable the window */
+	writel_relaxed(upper_32_bits(pci_addr),
+		       host->axi + RZG3S_PCI_AWBASEU(id));
+	writel_relaxed(lower_32_bits(pci_addr) | RZG3S_PCI_AWBASEL_WIN_ENA,
+		       host->axi + RZG3S_PCI_AWBASEL(id));
+}
+
+static int rzg3s_pcie_set_inbound_windows(struct rzg3s_pcie_host *host,
+					  struct resource_entry *entry,
+					  int *index)
+{
+	u64 pci_addr = entry->res->start - entry->offset;
+	u64 cpu_addr = entry->res->start;
+	u64 cpu_end = entry->res->end;
+	u64 size_id = 0;
+	int id = *index;
+	u64 size;
+
+	while (cpu_addr < cpu_end) {
+		if (id >= RZG3S_MAX_WINDOWS)
+			return dev_err_probe(host->dev, -ENOSPC,
+					     "Failed to map inbound window for resource (%s)\n",
+					     entry->res->name);
+
+		size = resource_size(entry->res) - size_id;
+
+		/*
+		 * According to the RZ/G3S HW manual (Rev.1.10,
+		 * section 34.3.1.71 AXI Window Mask (Lower) Registers) the min
+		 * size is 4K.
+		 */
+		size = max(size, SZ_4K);
+
+		/*
+		 * According the RZ/G3S HW manual (Rev.1.10, sections:
+		 * - 34.3.1.69 AXI Window Base (Lower) Registers
+		 * - 34.3.1.71 AXI Window Mask (Lower) Registers
+		 * - 34.3.1.73 AXI Destination (Lower) Registers)
+		 * the CPU addr, PCIe addr, size should be 4K aligned and be a
+		 * power of 2.
+		 */
+		size = ALIGN(size, SZ_4K);
+		size = roundup_pow_of_two(size);
+
+		cpu_addr = ALIGN(cpu_addr, SZ_4K);
+		pci_addr = ALIGN(pci_addr, SZ_4K);
+
+		/*
+		 * According to the RZ/G3S HW manual (Rev.1.10, section
+		 * 34.3.1.71 AXI Window Mask (Lower) Registers) HW expects first
+		 * 12 LSB bits to be 0xfff. Subtract 1 from size for this.
+		 */
+		rzg3s_pcie_set_inbound_window(host, cpu_addr, pci_addr,
+					      size - 1, id);
+
+		pci_addr += size;
+		cpu_addr += size;
+		size_id = size;
+		id++;
+	}
+	*index = id;
+
+	return 0;
+}
+
+static int rzg3s_pcie_parse_map_dma_ranges(struct rzg3s_pcie_host *host)
+{
+	struct pci_host_bridge *bridge = pci_host_bridge_from_priv(host);
+	struct resource_entry *entry;
+	int i = 0, ret;
+
+	resource_list_for_each_entry(entry, &bridge->dma_ranges) {
+		ret = rzg3s_pcie_set_inbound_windows(host, entry, &i);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void rzg3s_pcie_set_outbound_window(struct rzg3s_pcie_host *host,
+					   struct resource_entry *win, int id)
+{
+	struct resource *res = win->res;
+	resource_size_t size = resource_size(res);
+	resource_size_t res_start;
+
+	if (res->flags & IORESOURCE_IO)
+		res_start = pci_pio_to_address(res->start) - win->offset;
+	else
+		res_start = res->start - win->offset;
+
+	/*
+	 * According to the RZ/G3S HW manual (Rev.1.10, section 34.3.1.75 PCIe
+	 * Window Base (Lower) Registers) the window base address need to be 4K
+	 * aligned.
+	 */
+	res_start = ALIGN(res_start, SZ_4K);
+
+	size = ALIGN(size, SZ_4K);
+	size = roundup_pow_of_two(size) - 1;
+
+	/* Set PCIe destination */
+	writel_relaxed(upper_32_bits(res_start),
+		       host->axi + RZG3S_PCI_PDESTU(id));
+	writel_relaxed(lower_32_bits(res_start),
+		       host->axi + RZG3S_PCI_PDESTL(id));
+
+	/* Set PCIe window mask */
+	writel_relaxed(upper_32_bits(size), host->axi + RZG3S_PCI_PWMASKU(id));
+	writel_relaxed(lower_32_bits(size), host->axi + RZG3S_PCI_PWMASKL(id));
+
+	/* Set PCIe window base and enable the window */
+	writel_relaxed(upper_32_bits(res_start),
+		       host->axi + RZG3S_PCI_PWBASEU(id));
+	writel_relaxed(lower_32_bits(res_start) | RZG3S_PCI_PWBASEL_ENA,
+		       host->axi + RZG3S_PCI_PWBASEL(id));
+}
+
+static int rzg3s_pcie_parse_map_ranges(struct rzg3s_pcie_host *host)
+{
+	struct pci_host_bridge *bridge = pci_host_bridge_from_priv(host);
+	struct resource_entry *win;
+	int i = 0;
+
+	resource_list_for_each_entry(win, &bridge->windows) {
+		struct resource *res = win->res;
+
+		if (i >= RZG3S_MAX_WINDOWS)
+			return dev_err_probe(host->dev, -ENOSPC,
+					     "Failed to map outbound window for resource (%s)\n",
+					     res->name);
+
+		if (!res->flags)
+			continue;
+
+		switch (resource_type(res)) {
+		case IORESOURCE_IO:
+		case IORESOURCE_MEM:
+			rzg3s_pcie_set_outbound_window(host, win, i);
+			i++;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int rzg3s_soc_pcie_init_phy(struct rzg3s_pcie_host *host)
+{
+	static const u32 xcfgd_settings[RZG3S_PCI_PHY_XCFGD_NUM] = {
+		[8]  = 0xe0006801, 0x007f7e30, 0x183e0000, 0x978ff500,
+		       0xec000000, 0x009f1400, 0x0000d009,
+		[17] = 0x78000000,
+		[19] = 0x00880000, 0x000005c0, 0x07000000, 0x00780920,
+		       0xc9400ce2, 0x90000c0c, 0x000c1414, 0x00005034,
+		       0x00006000, 0x00000001,
+	};
+	static const u32 xcfga_cmn_settings[RZG3S_PCI_PHY_XCFGA_CMN_NUM] = {
+		0x00000d10, 0x08310100, 0x00c21404, 0x013c0010, 0x01874440,
+		0x1a216082, 0x00103440, 0x00000080, 0x00000010, 0x0c1000c1,
+		0x1000c100, 0x0222000c, 0x00640019, 0x00a00028, 0x01d11228,
+		0x0201001d,
+	};
+	static const u32 xcfga_rx_settings[RZG3S_PCI_PHY_XCFGA_RX_NUM] = {
+		0x07d55000, 0x030e3f00, 0x00000288, 0x102c5880, 0x0000000b,
+		0x04141441, 0x00641641, 0x00d63d63, 0x00641641, 0x01970377,
+		0x00190287, 0x00190028, 0x00000028,
+	};
+	unsigned int i;
+
+	/*
+	 * Enable access permission for physical layer control and status
+	 * registers.
+	 */
+	writel_relaxed(RZG3S_PCI_PERM_PIPE_PHY_REG_EN,
+		       host->axi + RZG3S_PCI_PERM);
+
+	for (i = 0; i < RZG3S_PCI_PHY_XCFGD_NUM; i++) {
+		writel_relaxed(xcfgd_settings[i],
+			       host->axi + RZG3S_PCI_PHY_XCFGD(i));
+	}
+
+	for (i = 0; i < RZG3S_PCI_PHY_XCFGA_CMN_NUM; i++) {
+		writel_relaxed(xcfga_cmn_settings[i],
+			       host->axi + RZG3S_PCI_PHY_XCFGA_CMN(i));
+	}
+
+	for (i = 0; i < RZG3S_PCI_PHY_XCFGA_RX_NUM; i++) {
+		writel_relaxed(xcfga_rx_settings[i],
+			       host->axi + RZG3S_PCI_PHY_XCFGA_RX(i));
+	}
+
+	writel_relaxed(0x107, host->axi + RZG3S_PCI_PHY_XCFGA_TX);
+
+	/* Select PHY settings values */
+	writel_relaxed(RZG3S_PCI_PHY_XCFG_CTRL_PHYREG_SEL,
+		       host->axi + RZG3S_PCI_PHY_XCFG_CTRL);
+
+	/*
+	 * Disable access permission for physical layer control and status
+	 * registers.
+	 */
+	writel_relaxed(0, host->axi + RZG3S_PCI_PERM);
+
+	return 0;
+}
+
+static int
+rzg3s_pcie_host_setup(struct rzg3s_pcie_host *host,
+		      int (*init_irqdomain)(struct rzg3s_pcie_host *host),
+		      void (*teardown_irqdomain)(struct rzg3s_pcie_host *host))
+{
+	struct device *dev = host->dev;
+	int ret;
+
+	/* Set inbound windows */
+	ret = rzg3s_pcie_parse_map_dma_ranges(host);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to set inbound windows!\n");
+
+	/* Set outbound windows */
+	ret = rzg3s_pcie_parse_map_ranges(host);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to set outbound windows!\n");
+
+	ret = init_irqdomain(host);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to init IRQ domain\n");
+
+	ret = rzg3s_pcie_host_init(host);
+	if (ret) {
+		dev_err_probe(dev, ret, "Failed to initialize the HW!\n");
+		goto teardown_irqdomain;
+	}
+
+	ret = rzg3s_pcie_set_max_link_speed(host);
+	if (ret)
+		dev_info(dev, "Failed to set max link speed\n");
+
+	msleep(PCIE_RESET_CONFIG_WAIT_MS);
+
+	return 0;
+
+teardown_irqdomain:
+	teardown_irqdomain(host);
+
+	return ret;
+}
+
+static int rzg3s_pcie_probe(struct platform_device *pdev)
+{
+	struct pci_host_bridge *bridge;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct device_node *sysc_np __free(device_node) =
+		of_parse_phandle(np, "renesas,sysc", 0);;
+	struct rzg3s_pcie_host *host;
+	int ret;
+
+	bridge = devm_pci_alloc_host_bridge(dev, sizeof(*host));
+	if (!bridge)
+		return -ENOMEM;
+
+	host = pci_host_bridge_priv(bridge);
+	host->dev = dev;
+	host->data = device_get_match_data(dev);
+	platform_set_drvdata(pdev, host);
+
+	host->axi = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(host->axi))
+		return PTR_ERR(host->axi);
+	host->pcie = host->axi + RZG3S_PCI_CFG_BASE;
+
+	host->max_link_speed = of_pci_get_max_link_speed(np);
+	if (host->max_link_speed < 0)
+		host->max_link_speed = 2;
+
+	ret = rzg3s_pcie_host_parse_port(host);
+	if (ret)
+		return ret;
+
+	sysc_np = of_parse_phandle(np, "renesas,sysc", 0);
+	host->sysc = syscon_node_to_regmap(sysc_np);
+	if (IS_ERR(host->sysc)) {
+		ret = PTR_ERR(host->sysc);
+		goto port_refclk_put;
+	}
+
+	ret = regmap_update_bits(host->sysc, RZG3S_SYS_PCIE_RST_RSM_B,
+				 RZG3S_SYS_PCIE_RST_RSM_B_MASK,
+				 FIELD_PREP(RZG3S_SYS_PCIE_RST_RSM_B_MASK, 1));
+	if (ret)
+		goto port_refclk_put;
+
+	ret = rzg3s_pcie_resets_prepare_and_get(host);
+	if (ret)
+		goto sysc_signal_restore;
+
+	ret = rzg3s_pcie_power_resets_deassert(host);
+	if (ret)
+		goto sysc_signal_restore;
+
+	pm_runtime_enable(dev);
+
+	/*
+	 * Controller clocks are part of a clock power domain. Enable them
+	 * through runtime PM.
+	 */
+	ret = pm_runtime_resume_and_get(dev);
+	if (ret)
+		goto rpm_disable;
+
+	raw_spin_lock_init(&host->hw_lock);
+
+	ret = rzg3s_pcie_host_setup(host, rzg3s_pcie_init_irqdomain,
+				    rzg3s_pcie_teardown_irqdomain);
+	if (ret)
+		goto rpm_put;
+
+	bridge->sysdata = host;
+	bridge->ops = &rzg3s_pcie_root_ops;
+	bridge->child_ops = &rzg3s_pcie_child_ops;
+	ret = pci_host_probe(bridge);
+	if (ret)
+		goto host_probe_teardown;
+
+	return 0;
+
+host_probe_teardown:
+	rzg3s_pcie_teardown_irqdomain(host);
+	reset_control_bulk_deassert(host->data->num_cfg_resets,
+				    host->cfg_resets);
+rpm_put:
+	pm_runtime_put_sync(dev);
+rpm_disable:
+	pm_runtime_disable(dev);
+	reset_control_bulk_assert(host->data->num_power_resets,
+				  host->power_resets);
+sysc_signal_restore:
+	/*
+	 * SYSC RST_RSM_B signal need to be asserted before turning off the
+	 * power to the PHY.
+	 */
+	regmap_update_bits(host->sysc, RZG3S_SYS_PCIE_RST_RSM_B,
+			   RZG3S_SYS_PCIE_RST_RSM_B_MASK,
+			   FIELD_PREP(RZG3S_SYS_PCIE_RST_RSM_B_MASK, 0));
+port_refclk_put:
+	clk_put(host->port.refclk);
+
+	return ret;
+}
+
+static int rzg3s_pcie_suspend_noirq(struct device *dev)
+{
+	struct rzg3s_pcie_host *host = dev_get_drvdata(dev);
+	const struct rzg3s_pcie_soc_data *data = host->data;
+	struct rzg3s_pcie_port *port = &host->port;
+	struct regmap *sysc = host->sysc;
+	int ret;
+
+	ret = pm_runtime_put_sync(dev);
+	if (ret)
+		return ret;
+
+	clk_disable_unprepare(port->refclk);
+
+	ret = reset_control_bulk_assert(data->num_power_resets,
+					host->power_resets);
+	if (ret)
+		goto refclk_restore;
+
+	ret = reset_control_bulk_assert(data->num_cfg_resets,
+					host->cfg_resets);
+	if (ret)
+		goto power_resets_restore;
+
+	ret = regmap_update_bits(sysc, RZG3S_SYS_PCIE_RST_RSM_B,
+				 RZG3S_SYS_PCIE_RST_RSM_B_MASK,
+				 FIELD_PREP(RZG3S_SYS_PCIE_RST_RSM_B_MASK, 0));
+	if (ret)
+		goto cfg_resets_restore;
+
+	return 0;
+
+	/* Restore the previous state if any error happens */
+cfg_resets_restore:
+	reset_control_bulk_deassert(data->num_cfg_resets,
+				    host->cfg_resets);
+power_resets_restore:
+	reset_control_bulk_deassert(data->num_power_resets,
+				    host->power_resets);
+refclk_restore:
+	clk_prepare_enable(port->refclk);
+	pm_runtime_resume_and_get(dev);
+	return ret;
+}
+
+static int rzg3s_pcie_resume_noirq(struct device *dev)
+{
+	struct rzg3s_pcie_host *host = dev_get_drvdata(dev);
+	const struct rzg3s_pcie_soc_data *data = host->data;
+	struct regmap *sysc = host->sysc;
+	int ret;
+
+	ret = regmap_update_bits(sysc, RZG3S_SYS_PCIE_RST_RSM_B,
+				 RZG3S_SYS_PCIE_RST_RSM_B_MASK,
+				 FIELD_PREP(RZG3S_SYS_PCIE_RST_RSM_B_MASK, 1));
+	if (ret)
+		return ret;
+
+	ret = rzg3s_pcie_power_resets_deassert(host);
+	if (ret)
+		goto assert_rst_rsm_b;
+
+	ret = pm_runtime_resume_and_get(dev);
+	if (ret)
+		goto assert_power_resets;
+
+	ret = rzg3s_pcie_host_setup(host, rzg3s_pcie_msi_hw_setup,
+				    rzg3s_pcie_msi_hw_teardown);
+	if (ret)
+		goto rpm_put;
+
+	return 0;
+
+	/*
+	 * If any error happens there is no way to recover the IP. Put it in the
+	 * lowest possible power state.
+	 */
+rpm_put:
+	pm_runtime_put_sync(dev);
+assert_power_resets:
+	reset_control_bulk_assert(data->num_power_resets,
+				  host->power_resets);
+assert_rst_rsm_b:
+	regmap_update_bits(sysc, RZG3S_SYS_PCIE_RST_RSM_B,
+			   RZG3S_SYS_PCIE_RST_RSM_B_MASK,
+			   FIELD_PREP(RZG3S_SYS_PCIE_RST_RSM_B_MASK, 0));
+	return ret;
+}
+
+static const struct dev_pm_ops rzg3s_pcie_pm_ops = {
+	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rzg3s_pcie_suspend_noirq,
+				      rzg3s_pcie_resume_noirq)
+};
+
+static const char * const rzg3s_soc_power_resets[] = {
+	"aresetn", "rst_cfg_b", "rst_load_b",
+};
+
+static const char * const rzg3s_soc_cfg_resets[] = {
+	"rst_b", "rst_ps_b", "rst_gp_b", "rst_rsm_b",
+};
+
+static const struct rzg3s_pcie_soc_data rzg3s_soc_data = {
+	.power_resets = rzg3s_soc_power_resets,
+	.num_power_resets = ARRAY_SIZE(rzg3s_soc_power_resets),
+	.cfg_resets = rzg3s_soc_cfg_resets,
+	.num_cfg_resets = ARRAY_SIZE(rzg3s_soc_cfg_resets),
+	.init_phy = rzg3s_soc_pcie_init_phy,
+};
+
+static const struct of_device_id rzg3s_pcie_of_match[] = {
+	{
+		.compatible = "renesas,r9a08g045-pcie",
+		.data = &rzg3s_soc_data,
+	},
+	{}
+};
+
+static struct platform_driver rzg3s_pcie_driver = {
+	.driver = {
+		.name = "rzg3s-pcie-host",
+		.of_match_table = rzg3s_pcie_of_match,
+		.pm = pm_ptr(&rzg3s_pcie_pm_ops),
+		.suppress_bind_attrs = true,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+	},
+	.probe = rzg3s_pcie_probe,
+};
+builtin_platform_driver(rzg3s_pcie_driver);
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 19/28] PCI: rzg3s-host: Initialize MSI status bitmap before use
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (17 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 18/28] PCI: Add Renesas RZ/G3S host controller driver Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 20/28] PCI: rzg3s-host: Use pci_generic_config_write() for the root bus Claudiu
                   ` (8 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

commit 94bf74830a977a027042f685c7231c5e07cc3372 upstream.

Initialize rzg3s_pcie_msi_irq() MSI status bitmap before use.

Fixes: 7ef502fb35b2 ("PCI: Add Renesas RZ/G3S host controller driver")
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/all/202512070218.XVMUQCl7-lkp@intel.com
Closes: https://lore.kernel.org/all/202512061812.Xbqmd2Gn-lkp@intel.com
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Link: https://patch.msgid.link/20251209125122.304129-1-claudiu.beznea.uj@bp.renesas.com
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 drivers/pci/controller/pcie-rzg3s-host.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c
index 124c07d72ff6..794515e5a6f0 100644
--- a/drivers/pci/controller/pcie-rzg3s-host.c
+++ b/drivers/pci/controller/pcie-rzg3s-host.c
@@ -481,7 +481,7 @@ static void rzg3s_pcie_intx_irq_handler(struct irq_desc *desc)
 static irqreturn_t rzg3s_pcie_msi_irq(int irq, void *data)
 {
 	u8 regs = RZG3S_PCI_MSI_INT_NR / RZG3S_PCI_MSI_INT_PER_REG;
-	DECLARE_BITMAP(bitmap, RZG3S_PCI_MSI_INT_NR);
+	DECLARE_BITMAP(bitmap, RZG3S_PCI_MSI_INT_NR) = {0};
 	struct rzg3s_pcie_host *host = data;
 	struct rzg3s_pcie_msi *msi = &host->msi;
 	unsigned long bit;
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 20/28] PCI: rzg3s-host: Use pci_generic_config_write() for the root bus
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (18 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 19/28] PCI: rzg3s-host: Initialize MSI status bitmap before use Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 21/28] PCI: rzg3s-host: Drop the lock on RZG3S_PCI_MSIRS and RZG3S_PCI_PINTRCVIS Claudiu
                   ` (7 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

commit 4b86eff47e205819eb862097493ec20e25ac8f56 upstream.

The Renesas RZ/G3S host controller allows writing to read-only PCIe
configuration registers when the RZG3S_PCI_PERM_CFG_HWINIT_EN bit is set in
the RZG3S_PCI_PERM register. However, callers of struct pci_ops::write
expect the semantics defined by the PCIe specification, meaning that writes
to read-only registers must not be allowed.

The previous custom struct pci_ops::write implementation for the root bus
temporarily enabled write access before calling pci_generic_config_write().
This breaks the expected semantics.

Remove the custom implementation and simply use pci_generic_config_write().

Along with this change, the updates of the PCI_PRIMARY_BUS,
PCI_SECONDARY_BUS, and PCI_SUBORDINATE_BUS registers were moved so that
they no longer depends on the RZG3S_PCI_PERM_CFG_HWINIT_EN bit in the
RZG3S_PCI_PERM_CFG register, since these registers are R/W.

Fixes: 7ef502fb35b2 ("PCI: Add Renesas RZ/G3S host controller driver")
Suggested-by: Bjorn Helgaas <helgaas@kernel.org>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Link: https://patch.msgid.link/20251217111510.138848-2-claudiu.beznea.uj@bp.renesas.com
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 drivers/pci/controller/pcie-rzg3s-host.c | 27 ++++--------------------
 1 file changed, 4 insertions(+), 23 deletions(-)

diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c
index 794515e5a6f0..8291f4642c91 100644
--- a/drivers/pci/controller/pcie-rzg3s-host.c
+++ b/drivers/pci/controller/pcie-rzg3s-host.c
@@ -438,28 +438,9 @@ static void __iomem *rzg3s_pcie_root_map_bus(struct pci_bus *bus,
 	return host->pcie + where;
 }
 
-/* Serialized by 'pci_lock' */
-static int rzg3s_pcie_root_write(struct pci_bus *bus, unsigned int devfn,
-				 int where, int size, u32 val)
-{
-	struct rzg3s_pcie_host *host = bus->sysdata;
-	int ret;
-
-	/* Enable access control to the CFGU */
-	writel_relaxed(RZG3S_PCI_PERM_CFG_HWINIT_EN,
-		       host->axi + RZG3S_PCI_PERM);
-
-	ret = pci_generic_config_write(bus, devfn, where, size, val);
-
-	/* Disable access control to the CFGU */
-	writel_relaxed(0, host->axi + RZG3S_PCI_PERM);
-
-	return ret;
-}
-
 static struct pci_ops rzg3s_pcie_root_ops = {
 	.read		= pci_generic_config_read,
-	.write		= rzg3s_pcie_root_write,
+	.write		= pci_generic_config_write,
 	.map_bus	= rzg3s_pcie_root_map_bus,
 };
 
@@ -1104,14 +1085,14 @@ static int rzg3s_pcie_config_init(struct rzg3s_pcie_host *host)
 	writel_relaxed(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00L);
 	writel_relaxed(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00U);
 
+	/* Disable access control to the CFGU */
+	writel_relaxed(0, host->axi + RZG3S_PCI_PERM);
+
 	/* Update bus info */
 	writeb_relaxed(primary_bus, host->pcie + PCI_PRIMARY_BUS);
 	writeb_relaxed(secondary_bus, host->pcie + PCI_SECONDARY_BUS);
 	writeb_relaxed(subordinate_bus, host->pcie + PCI_SUBORDINATE_BUS);
 
-	/* Disable access control to the CFGU */
-	writel_relaxed(0, host->axi + RZG3S_PCI_PERM);
-
 	return 0;
 }
 
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 21/28] PCI: rzg3s-host: Drop the lock on RZG3S_PCI_MSIRS and RZG3S_PCI_PINTRCVIS
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (19 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 20/28] PCI: rzg3s-host: Use pci_generic_config_write() for the root bus Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 22/28] PCI: rzg3s-host: Fix device node reference leak in rzg3s_pcie_host_parse_port() Claudiu
                   ` (6 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

commit 62d4911290f9cbb16f5b6ba6782660148a656fc7 upstream.

The RZG3S_PCI_MSIRS and RZG3S_PCI_PINTRCVIS registers are of the R/W1C
type. According to the RZ/G3S HW Manual, Rev. 1.10, chapter 34.2.1
Register Type, R/W1C register bits are cleared to 0b by writing 1b, while
writing 0b has no effect. Therefore, there is no need to take a lock
around writes to these registers.

Drop the locking.

Along with this, add a note about the R/W1C register type to the register
offset definitions.

Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Link: https://patch.msgid.link/20251217111510.138848-3-claudiu.beznea.uj@bp.renesas.com
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 drivers/pci/controller/pcie-rzg3s-host.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c
index 8291f4642c91..80d4a4623ccc 100644
--- a/drivers/pci/controller/pcie-rzg3s-host.c
+++ b/drivers/pci/controller/pcie-rzg3s-host.c
@@ -72,6 +72,7 @@
 #define RZG3S_PCI_PINTRCVIE_INTX(i)		BIT(i)
 #define RZG3S_PCI_PINTRCVIE_MSI			BIT(4)
 
+/* Register is R/W1C, it doesn't require locking. */
 #define RZG3S_PCI_PINTRCVIS			0x114
 #define RZG3S_PCI_PINTRCVIS_INTX(i)		BIT(i)
 #define RZG3S_PCI_PINTRCVIS_MSI			BIT(4)
@@ -113,6 +114,8 @@
 #define RZG3S_PCI_MSIRE_ENA			BIT(0)
 
 #define RZG3S_PCI_MSIRM(id)			(0x608 + (id) * 0x10)
+
+/* Register is R/W1C, it doesn't require locking. */
 #define RZG3S_PCI_MSIRS(id)			(0x60c + (id) * 0x10)
 
 #define RZG3S_PCI_AWBASEL(id)			(0x1000 + (id) * 0x20)
@@ -536,8 +539,6 @@ static void rzg3s_pcie_msi_irq_ack(struct irq_data *d)
 	u8 reg_bit = d->hwirq % RZG3S_PCI_MSI_INT_PER_REG;
 	u8 reg_id = d->hwirq / RZG3S_PCI_MSI_INT_PER_REG;
 
-	guard(raw_spinlock_irqsave)(&host->hw_lock);
-
 	writel_relaxed(BIT(reg_bit), host->axi + RZG3S_PCI_MSIRS(reg_id));
 }
 
@@ -878,8 +879,6 @@ static void rzg3s_pcie_intx_irq_ack(struct irq_data *d)
 {
 	struct rzg3s_pcie_host *host = irq_data_get_irq_chip_data(d);
 
-	guard(raw_spinlock_irqsave)(&host->hw_lock);
-
 	rzg3s_pcie_update_bits(host->axi, RZG3S_PCI_PINTRCVIS,
 			       RZG3S_PCI_PINTRCVIS_INTX(d->hwirq),
 			       RZG3S_PCI_PINTRCVIS_INTX(d->hwirq));
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 22/28] PCI: rzg3s-host: Fix device node reference leak in rzg3s_pcie_host_parse_port()
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (20 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 21/28] PCI: rzg3s-host: Drop the lock on RZG3S_PCI_MSIRS and RZG3S_PCI_PINTRCVIS Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 23/28] arm64: dts: renesas: r9a08g045: Enable SYS node Claudiu
                   ` (5 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Felix Gu <ustc.gu@gmail.com>

commit e43e2aa557040bbcc5de0eaa1c59ee3ae9e31793 upstream.

In rzg3s_pcie_host_parse_port(), of_get_next_child() returns a device node
with an incremented reference count that must be released with
of_node_put(). The current code fails to call of_node_put() which causes a
reference leak.

Use the __free(device_node) attribute to ensure automatic cleanup when the
variable goes out of scope.

Fixes: 7ef502fb35b2 ("PCI: Add Renesas RZ/G3S host controller driver")
Signed-off-by: Felix Gu <ustc.gu@gmail.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Acked-by: Manivannan Sadhasivam <mani@kernel.org>
Link: https://patch.msgid.link/20260204-rzg3s-v1-1-142bc81c3312@gmail.com
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 drivers/pci/controller/pcie-rzg3s-host.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c
index 80d4a4623ccc..987015e8ec9b 100644
--- a/drivers/pci/controller/pcie-rzg3s-host.c
+++ b/drivers/pci/controller/pcie-rzg3s-host.c
@@ -1181,7 +1181,8 @@ static int rzg3s_pcie_resets_prepare_and_get(struct rzg3s_pcie_host *host)
 
 static int rzg3s_pcie_host_parse_port(struct rzg3s_pcie_host *host)
 {
-	struct device_node *of_port = of_get_next_child(host->dev->of_node, NULL);
+	struct device_node *of_port __free(device_node) =
+		of_get_next_child(host->dev->of_node, NULL);
 	struct rzg3s_pcie_port *port = &host->port;
 	int ret;
 
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 23/28] arm64: dts: renesas: r9a08g045: Enable SYS node
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (21 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 22/28] PCI: rzg3s-host: Fix device node reference leak in rzg3s_pcie_host_parse_port() Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 24/28] arm64: dts: renesas: r9a08g045: Use syscon compatible for the system controller Claudiu
                   ` (4 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

commit 495af7647560c2b3a9c3107ea81dfd7d7c8a38c0 upstream.

Enable the System Controller.  It is needed for SoC identification.

Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Signed-off-by: John Madieu <john.madieu.xa@bp.renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Link: https://lore.kernel.org/20250123170508.13578-8-john.madieu.xa@bp.renesas.com
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 arch/arm64/boot/dts/renesas/r9a08g045.dtsi | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/arm64/boot/dts/renesas/r9a08g045.dtsi b/arch/arm64/boot/dts/renesas/r9a08g045.dtsi
index e56f1bf311ec..ddb2477675ec 100644
--- a/arch/arm64/boot/dts/renesas/r9a08g045.dtsi
+++ b/arch/arm64/boot/dts/renesas/r9a08g045.dtsi
@@ -481,7 +481,6 @@ sysc: system-controller@11020000 {
 				     <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
 			interrupt-names = "lpm_int", "ca55stbydone_int",
 					  "cm33stbyr_int", "ca55_deny";
-			status = "disabled";
 		};
 
 		pinctrl: pinctrl@11030000 {
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 24/28] arm64: dts: renesas: r9a08g045: Use syscon compatible for the system controller
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (22 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 23/28] arm64: dts: renesas: r9a08g045: Enable SYS node Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 25/28] arm64: dts: renesas: r9a08g045: Add PCIe node Claudiu
                   ` (3 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

RZ/G3S PCIe driver needs the system controller syscon to be able to set
its registers. For this, it uses syscon_node_to_regmap(). But, in v6.1
CIP, the syscon_node_to_regmap() returns ERR_PTR(-EINVAL) if the node
for which it is called don't have the syscon compatible.

Add syscon compatible for the system controller.

Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 arch/arm64/boot/dts/renesas/r9a08g045.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/renesas/r9a08g045.dtsi b/arch/arm64/boot/dts/renesas/r9a08g045.dtsi
index ddb2477675ec..8d90ea8a82c9 100644
--- a/arch/arm64/boot/dts/renesas/r9a08g045.dtsi
+++ b/arch/arm64/boot/dts/renesas/r9a08g045.dtsi
@@ -473,7 +473,7 @@ cpg: clock-controller@11010000 {
 		};
 
 		sysc: system-controller@11020000 {
-			compatible = "renesas,r9a08g045-sysc";
+			compatible = "renesas,r9a08g045-sysc", "syscon";
 			reg = <0 0x11020000 0 0x10000>;
 			interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 25/28] arm64: dts: renesas: r9a08g045: Add PCIe node
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (23 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 24/28] arm64: dts: renesas: r9a08g045: Use syscon compatible for the system controller Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 26/28] arm64: dts: renesas: rzg3s-smarc-som: Add PCIe reference clock Claudiu
                   ` (2 subsequent siblings)
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

commit 40a4c75e7f7170f4dc9f077ae480fe5775a780a1 upstream.

The RZ/G3S SoC has a variant (R9A08G045S33) which supports PCIe. Add the
PCIe node.

Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Acked-by: Manivannan Sadhasivam <mani@kernel.org>
Link: https://patch.msgid.link/20251119143523.977085-4-claudiu.beznea.uj@bp.renesas.com
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
[claudiu.beznea: fixed conflict by dropping the USB nodes as these are
 not yet present in v5.10 CIP]
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 arch/arm64/boot/dts/renesas/r9a08g045.dtsi | 65 ++++++++++++++++++++++
 1 file changed, 65 insertions(+)

diff --git a/arch/arm64/boot/dts/renesas/r9a08g045.dtsi b/arch/arm64/boot/dts/renesas/r9a08g045.dtsi
index 8d90ea8a82c9..ecca25467163 100644
--- a/arch/arm64/boot/dts/renesas/r9a08g045.dtsi
+++ b/arch/arm64/boot/dts/renesas/r9a08g045.dtsi
@@ -691,6 +691,71 @@ eth1: ethernet@11c40000 {
 			status = "disabled";
 		};
 
+		pcie: pcie@11e40000 {
+			compatible = "renesas,r9a08g045-pcie";
+			reg = <0 0x11e40000 0 0x10000>;
+			ranges = <0x02000000 0 0x30000000 0 0x30000000 0 0x08000000>;
+			/* Map all possible DRAM ranges (4 GB). */
+			dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 1 0x00000000>;
+			bus-range = <0x0 0xff>;
+			interrupts = <GIC_SPI 395 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 396 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 397 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 398 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 399 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 401 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 402 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 403 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 404 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 405 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 409 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 410 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "serr", "serr_cor", "serr_nonfatal",
+					  "serr_fatal", "axi_err", "inta",
+					  "intb", "intc", "intd", "msi",
+					  "link_bandwidth", "pm_pme", "dma",
+					  "pcie_evt", "msg", "all";
+			#interrupt-cells = <1>;
+			interrupt-controller;
+			interrupt-map-mask = <0 0 0 7>;
+			interrupt-map = <0 0 0 1 &pcie 0 0 0 0>, /* INTA */
+					<0 0 0 2 &pcie 0 0 0 1>, /* INTB */
+					<0 0 0 3 &pcie 0 0 0 2>, /* INTC */
+					<0 0 0 4 &pcie 0 0 0 3>; /* INTD */
+			clocks = <&cpg CPG_MOD R9A08G045_PCI_ACLK>,
+				 <&cpg CPG_MOD R9A08G045_PCI_CLKL1PM>;
+			clock-names = "aclk", "pm";
+			resets = <&cpg R9A08G045_PCI_ARESETN>,
+				 <&cpg R9A08G045_PCI_RST_B>,
+				 <&cpg R9A08G045_PCI_RST_GP_B>,
+				 <&cpg R9A08G045_PCI_RST_PS_B>,
+				 <&cpg R9A08G045_PCI_RST_RSM_B>,
+				 <&cpg R9A08G045_PCI_RST_CFG_B>,
+				 <&cpg R9A08G045_PCI_RST_LOAD_B>;
+			reset-names = "aresetn", "rst_b", "rst_gp_b", "rst_ps_b",
+				      "rst_rsm_b", "rst_cfg_b", "rst_load_b";
+			power-domains = <&cpg>;
+			device_type = "pci";
+			#address-cells = <3>;
+			#size-cells = <2>;
+			renesas,sysc = <&sysc>;
+			status = "disabled";
+
+			pcie_port0: pcie@0,0 {
+				reg = <0x0 0x0 0x0 0x0 0x0>;
+				ranges;
+				device_type = "pci";
+				vendor-id = <0x1912>;
+				device-id = <0x0033>;
+				#address-cells = <3>;
+				#size-cells = <2>;
+			};
+		};
+
 		gic: interrupt-controller@12400000 {
 			compatible = "arm,gic-v3";
 			#interrupt-cells = <3>;
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 26/28] arm64: dts: renesas: rzg3s-smarc-som: Add PCIe reference clock
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (24 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 25/28] arm64: dts: renesas: r9a08g045: Add PCIe node Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 27/28] arm64: dts: renesas: rzg3s-smarc: Enable PCIe Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 28/28] arm64: defconfig: Enable PCIe for the Renesas RZ/G3S SoC Claudiu
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

commit 1a66160fb28abcd228f69e00bb183a4749f23805 upstream.

Versa3 clock generator available on RZ/G3S SMARC Module provides the
reference clock for SoC PCIe interface. Update the device tree to reflect
this connection.

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Acked-by: Manivannan Sadhasivam <mani@kernel.org>
Link: https://patch.msgid.link/20251119143523.977085-5-claudiu.beznea.uj@bp.renesas.com
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi b/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi
index 7c40532fc869..b11f2e49748b 100644
--- a/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi
+++ b/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi
@@ -170,6 +170,11 @@ a0 80 30 30 9c
 	};
 };
 
+&pcie_port0 {
+	clocks = <&versa3 5>;
+	clock-names = "ref";
+};
+
 #if SW_CONFIG2 == SW_ON
 /* SD0 slot */
 &sdhi0 {
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 27/28] arm64: dts: renesas: rzg3s-smarc: Enable PCIe
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (25 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 26/28] arm64: dts: renesas: rzg3s-smarc-som: Add PCIe reference clock Claudiu
@ 2026-03-11 11:03 ` Claudiu
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 28/28] arm64: defconfig: Enable PCIe for the Renesas RZ/G3S SoC Claudiu
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

commit 73b73af99a49fd7bf0515741734660973fa2002a upstream.

The RZ Smarc Carrier-II board has PCIe headers mounted on it. Enable PCIe
support.

Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Acked-by: Manivannan Sadhasivam <mani@kernel.org>
Link: https://patch.msgid.link/20251119143523.977085-6-claudiu.beznea.uj@bp.renesas.com
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
[claudiu.beznea: fixed conflict by dropping I2C1 and USB nodes as these
 are not present in v5.10 CIP]
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi b/arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi
index c8800c41b4e7..203656961bdf 100644
--- a/arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi
+++ b/arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi
@@ -123,6 +123,12 @@ da7212: codec@1a {
 	};
 };
 
+&pcie {
+	pinctrl-0 = <&pcie_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
 &pinctrl {
 	audio_clock_pins: audio-clock {
 		pins = "AUDIO_CLK1", "AUDIO_CLK2";
@@ -150,6 +156,11 @@ key-3-gpio-hog {
 		line-name = "key-3-gpio-irq";
 	};
 
+	pcie_pins: pcie {
+		pinmux = <RZG2L_PORT_PINMUX(13, 2, 2)>, /* PCIE_RST_OUT_B */
+			 <RZG2L_PORT_PINMUX(13, 3, 2)>; /* PCIE_CLKREQ_B */
+	};
+
 	scif0_pins: scif0 {
 		pinmux = <RZG2L_PORT_PINMUX(6, 3, 1)>, /* RXD */
 			 <RZG2L_PORT_PINMUX(6, 4, 1)>; /* TXD */
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5.10.y-cip 28/28] arm64: defconfig: Enable PCIe for the Renesas RZ/G3S SoC
  2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
                   ` (26 preceding siblings ...)
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 27/28] arm64: dts: renesas: rzg3s-smarc: Enable PCIe Claudiu
@ 2026-03-11 11:03 ` Claudiu
  27 siblings, 0 replies; 37+ messages in thread
From: Claudiu @ 2026-03-11 11:03 UTC (permalink / raw)
  To: nobuhiro.iwamatsu.x90, pavel; +Cc: cip-dev

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

commit fc913a1c9df1216db1e33dcea4eb864fd0ca794a upstream.

Enable PCIe for the Renesas RZ/G3S SoC.

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Acked-by: Manivannan Sadhasivam <mani@kernel.org>
Link: https://patch.msgid.link/20251119143523.977085-7-claudiu.beznea.uj@bp.renesas.com
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
[claudiu.beznea: fixed conflict by keeping CONFIG_PCI_HOST_GENERIC and
 dropping CONFIG_PCIE_ROCKCHIP_HOST]
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 9e14e4605367..6aec23945cad 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -213,6 +213,7 @@ CONFIG_PCI_AARDVARK=y
 CONFIG_PCI_TEGRA=y
 CONFIG_PCIE_RCAR_HOST=y
 CONFIG_PCIE_RCAR_EP=y
+CONFIG_PCIE_RENESAS_RZG3S_HOST=y
 CONFIG_PCI_HOST_GENERIC=y
 CONFIG_PCI_XGENE=y
 CONFIG_PCIE_ALTERA=y
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* Re: [PATCH 5.10.y-cip 05/28] soc: renesas: rz-sysc: Populate readable_reg/writeable_reg in regmap config
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 05/28] soc: renesas: rz-sysc: Populate readable_reg/writeable_reg in regmap config Claudiu
@ 2026-03-24  9:26   ` Pavel Machek
  2026-03-25  8:35     ` Claudiu Beznea
  0 siblings, 1 reply; 37+ messages in thread
From: Pavel Machek @ 2026-03-24  9:26 UTC (permalink / raw)
  To: Claudiu; +Cc: nobuhiro.iwamatsu.x90, pavel, cip-dev

[-- Attachment #1: Type: text/plain, Size: 2014 bytes --]

Hi1

> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> 
> commit c432180a7d95081353a96fd6d5bd75b0fc8a27c3 upstream.
> 
> Not all system controller registers are accessible from Linux. Accessing
> such registers generates synchronous external abort. Populate the
> readable_reg and writeable_reg members of the regmap config to inform the
> regmap core which registers can be accessed. The list will need to be
> updated whenever new system controller functionality is exported through
> regmap.
> 

> +++ b/drivers/soc/renesas/r9a08g045-sysc.c
> @@ -18,7 +37,57 @@ static const struct rz_sysc_soc_id_init_data rzg3s_sysc_soc_id_init_data __initc
>  	.specific_id_mask = GENMASK(27, 0),
>  };
>  
> +static bool rzg3s_regmap_readable_reg(struct device *dev, 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_GETH0_CFG:
> +	case SYS_GETH1_CFG:
> +	case SYS_PCIE_CFG:
> +	case SYS_PCIE_MON:
> +	case SYS_PCIE_ERR_MON:
> +	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_writeable_reg(struct device *dev, 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;
> +	}
> +}

I'd not mind refactoring these two so that code could be shared.

Thanks and best regards,
								Pavel

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5.10.y-cip 07/28] lib/bitmap: add bitmap_{read,write}()
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 07/28] lib/bitmap: add bitmap_{read,write}() Claudiu
@ 2026-03-24  9:29   ` Pavel Machek
  2026-03-25  8:37     ` Claudiu Beznea
  0 siblings, 1 reply; 37+ messages in thread
From: Pavel Machek @ 2026-03-24  9:29 UTC (permalink / raw)
  To: Claudiu; +Cc: nobuhiro.iwamatsu.x90, pavel, cip-dev

[-- Attachment #1: Type: text/plain, Size: 2418 bytes --]

Hi!

> From: Syed Nayyar Waris <syednwaris@gmail.com>
> 
> commit 63c15822b8dd02a2423cfd92232245ace3f7a11b upstream.
> 
> The two new functions allow reading/writing values of length up to
> BITS_PER_LONG bits at arbitrary position in the bitmap.
> 
> The code was taken from "bitops: Introduce the for_each_set_clump macro"
> by Syed Nayyar Waris with a number of changes and simplifications:
>  - instead of using roundup(), which adds an unnecessary dependency
>    on <linux/math.h>, we calculate space as BITS_PER_LONG-offset;
>  - indentation is reduced by not using else-clauses (suggested by
>    checkpatch for bitmap_get_value());
>  - bitmap_get_value()/bitmap_set_value() are renamed to bitmap_read()
>    and bitmap_write();
>  - some redundant computations are omitted.
> 
> +++ b/include/linux/bitmap.h
> @@ -601,6 +605,79 @@ static inline void bitmap_set_value8(unsigned long *map, unsigned long value,
>  	map[index] |= value << offset;
>  }
>  
> +/**
> + * bitmap_read - read a value of n-bits from the memory region
> + * @map: address to the bitmap memory region
> + * @start: bit offset of the n-bit value
> + * @nbits: size of value in bits, nonzero, up to BITS_PER_LONG
> + *
> + * Returns: value of @nbits bits located at the @start bit offset within the
> + * @map memory region. For @nbits = 0 and @nbits > BITS_PER_LONG the return
> + * value is undefined.
> + */
> +static inline unsigned long bitmap_read(const unsigned long *map,
> +					unsigned long start,
> +					unsigned long nbits)
> +{
> +	size_t index = BIT_WORD(start);
> +	unsigned long offset = start % BITS_PER_LONG;
> +	unsigned long space = BITS_PER_LONG - offset;
> +	unsigned long value_low, value_high;
> +
> +	if (unlikely(!nbits || nbits > BITS_PER_LONG))
> +		return 0;

If someone attempts to read more than bits_per_long, we silently give
him 0. That sounds like recipe for hard-to-debug problem when the code
designed for 64-bit system is ran on 32-bit.

I'd expect WARN_ON here.

> +static inline void bitmap_write(unsigned long *map, unsigned long value,
> +				unsigned long start, unsigned long nbits)
> +{
> +	size_t index;
> +	unsigned long offset;
> +	unsigned long space;
> +	unsigned long mask;
> +	bool fit;
> +
> +	if (unlikely(!nbits || nbits > BITS_PER_LONG))
> +		return;

And similary here.

Thanks and best regards,
								Pavel

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5.10.y-cip 09/28] PCI: Add PCIE_RESET_CONFIG_DEVICE_WAIT_MS waiting time value
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 09/28] PCI: Add PCIE_RESET_CONFIG_DEVICE_WAIT_MS waiting time value Claudiu
@ 2026-03-24  9:33   ` Pavel Machek
  2026-03-25  8:36     ` Claudiu Beznea
  0 siblings, 1 reply; 37+ messages in thread
From: Pavel Machek @ 2026-03-24  9:33 UTC (permalink / raw)
  To: Claudiu; +Cc: nobuhiro.iwamatsu.x90, pavel, cip-dev

[-- Attachment #1: Type: text/plain, Size: 2626 bytes --]

Hi!

> commit d5ceb9496c565eb5763c127c6eb2d2b3068ab1df upstream.
> 
> Add the PCIE_RESET_CONFIG_DEVICE_WAIT_MS macro to define the minimum
> waiting time between exit from a conventional reset and sending the
> first configuration request to the device.
> 
> As described in PCIe r6.0, sec 6.6.1 <Conventional Reset>, there are two
> different use cases of the value:
> 
>    - "With a Downstream Port that does not support Link speeds greater
>      than 5.0 GT/s, software must wait a minimum of 100 ms following exit
>      from a Conventional Reset before sending a Configuration Request to
>      the device immediately below that Port."
> 
>    - "With a Downstream Port that supports Link speeds greater than
>      5.0 GT/s, software must wait a minimum of 100 ms after Link training
>      completes before sending a Configuration Request to the device
>      immediately below that Port."
> 
> [kwilczynski: commit log]
> Link: https://lore.kernel.org/linux-pci/20240328091835.14797-21-minda.chen@starfivetech.com
> Signed-off-by: Kevin Xie <kevin.xie@starfivetech.com>
> Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
> Reviewed-by: Mason Huo <mason.huo@starfivetech.com>
> [claudiu.beznea: fixed conflict by keeping only the definition for
>  PCIE_RESET_CONFIG_DEVICE_WAIT_MS]

I don't understand the message here. Upstream patch seems to be
identical to this one, but context differs.

Thanks and best regards,
								Pavel

> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index c2fd92a9ee1a..a391e4db9401 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -11,6 +11,21 @@
>  
>  #define PCI_VSEC_ID_INTEL_TBT	0x1234	/* Thunderbolt */
>  
> +/*
> + * PCIe r6.0, sec 6.6.1 <Conventional Reset>
> + *
> + * - "With a Downstream Port that does not support Link speeds greater
> + *    than 5.0 GT/s, software must wait a minimum of 100 ms following exit
> + *    from a Conventional Reset before sending a Configuration Request to
> + *    the device immediately below that Port."
> + *
> + * - "With a Downstream Port that supports Link speeds greater than
> + *    5.0 GT/s, software must wait a minimum of 100 ms after Link training
> + *    completes before sending a Configuration Request to the device
> + *    immediately below that Port."
> + */
> +#define PCIE_RESET_CONFIG_DEVICE_WAIT_MS	100
> +
>  extern const unsigned char pcie_link_speed[];
>  extern bool pci_early_dump;
>  

-- 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5.10.y-cip 12/28] reset: make shared pulsed reset controls re-triggerable
  2026-03-11 11:03 ` [PATCH 5.10.y-cip 12/28] reset: make shared pulsed reset controls re-triggerable Claudiu
@ 2026-03-24  9:37   ` Pavel Machek
  2026-03-25  8:35     ` Claudiu Beznea
  0 siblings, 1 reply; 37+ messages in thread
From: Pavel Machek @ 2026-03-24  9:37 UTC (permalink / raw)
  To: Claudiu; +Cc: nobuhiro.iwamatsu.x90, pavel, cip-dev

[-- Attachment #1: Type: text/plain, Size: 463 bytes --]

Hi!

> diff --git a/drivers/reset/core.c b/drivers/reset/core.c
> index 662867435fbe..4d1cd09096f5 100644
> --- a/drivers/reset/core.c
> +++ b/drivers/reset/core.c
> @@ -325,6 +358,46 @@ int reset_control_reset(struct reset_control *rstc)
>  }
>  EXPORT_SYMBOL_GPL(reset_control_reset);
>  
> +/**
> + * reset_control_rearm - allow shared reset line to be re-triggered"

O guess " should be deleted here.

Thanks and best regards,
									Pavel

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5.10.y-cip 12/28] reset: make shared pulsed reset controls re-triggerable
  2026-03-24  9:37   ` Pavel Machek
@ 2026-03-25  8:35     ` Claudiu Beznea
  0 siblings, 0 replies; 37+ messages in thread
From: Claudiu Beznea @ 2026-03-25  8:35 UTC (permalink / raw)
  To: Pavel Machek; +Cc: nobuhiro.iwamatsu.x90, cip-dev

Hi, Pavel,

On 3/24/26 11:37, Pavel Machek wrote:
> Hi!
> 
>> diff --git a/drivers/reset/core.c b/drivers/reset/core.c
>> index 662867435fbe..4d1cd09096f5 100644
>> --- a/drivers/reset/core.c
>> +++ b/drivers/reset/core.c
>> @@ -325,6 +358,46 @@ int reset_control_reset(struct reset_control *rstc)
>>   }
>>   EXPORT_SYMBOL_GPL(reset_control_reset);
>>   
>> +/**
>> + * reset_control_rearm - allow shared reset line to be re-triggered"

I'll send an upstream patch for it.

Thank you for your review,
Claudiu


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5.10.y-cip 05/28] soc: renesas: rz-sysc: Populate readable_reg/writeable_reg in regmap config
  2026-03-24  9:26   ` Pavel Machek
@ 2026-03-25  8:35     ` Claudiu Beznea
  0 siblings, 0 replies; 37+ messages in thread
From: Claudiu Beznea @ 2026-03-25  8:35 UTC (permalink / raw)
  To: Pavel Machek; +Cc: nobuhiro.iwamatsu.x90, cip-dev

Hi, Pavel,

On 3/24/26 11:26, Pavel Machek wrote:
> Hi1
> 
>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>>
>> commit c432180a7d95081353a96fd6d5bd75b0fc8a27c3 upstream.
>>
>> Not all system controller registers are accessible from Linux. Accessing
>> such registers generates synchronous external abort. Populate the
>> readable_reg and writeable_reg members of the regmap config to inform the
>> regmap core which registers can be accessed. The list will need to be
>> updated whenever new system controller functionality is exported through
>> regmap.
>>
> 
>> +++ b/drivers/soc/renesas/r9a08g045-sysc.c
>> @@ -18,7 +37,57 @@ static const struct rz_sysc_soc_id_init_data rzg3s_sysc_soc_id_init_data __initc
>>   	.specific_id_mask = GENMASK(27, 0),
>>   };
>>   
>> +static bool rzg3s_regmap_readable_reg(struct device *dev, 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_GETH0_CFG:
>> +	case SYS_GETH1_CFG:
>> +	case SYS_PCIE_CFG:
>> +	case SYS_PCIE_MON:
>> +	case SYS_PCIE_ERR_MON:
>> +	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_writeable_reg(struct device *dev, 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;
>> +	}
>> +}
> 
> I'd not mind refactoring these two so that code could be shared.

OK, I'm going to prepare something for upstream.

Thank you for your review,
Claudiu


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5.10.y-cip 09/28] PCI: Add PCIE_RESET_CONFIG_DEVICE_WAIT_MS waiting time value
  2026-03-24  9:33   ` Pavel Machek
@ 2026-03-25  8:36     ` Claudiu Beznea
  0 siblings, 0 replies; 37+ messages in thread
From: Claudiu Beznea @ 2026-03-25  8:36 UTC (permalink / raw)
  To: Pavel Machek; +Cc: nobuhiro.iwamatsu.x90, cip-dev

Hi, Pavel,

On 3/24/26 11:33, Pavel Machek wrote:
> Hi!
> 
>> commit d5ceb9496c565eb5763c127c6eb2d2b3068ab1df upstream.
>>
>> Add the PCIE_RESET_CONFIG_DEVICE_WAIT_MS macro to define the minimum
>> waiting time between exit from a conventional reset and sending the
>> first configuration request to the device.
>>
>> As described in PCIe r6.0, sec 6.6.1 <Conventional Reset>, there are two
>> different use cases of the value:
>>
>>     - "With a Downstream Port that does not support Link speeds greater
>>       than 5.0 GT/s, software must wait a minimum of 100 ms following exit
>>       from a Conventional Reset before sending a Configuration Request to
>>       the device immediately below that Port."
>>
>>     - "With a Downstream Port that supports Link speeds greater than
>>       5.0 GT/s, software must wait a minimum of 100 ms after Link training
>>       completes before sending a Configuration Request to the device
>>       immediately below that Port."
>>
>> [kwilczynski: commit log]
>> Link: https://lore.kernel.org/linux-pci/20240328091835.14797-21-minda.chen@starfivetech.com
>> Signed-off-by: Kevin Xie <kevin.xie@starfivetech.com>
>> Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
>> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
>> Reviewed-by: Mason Huo <mason.huo@starfivetech.com>
>> [claudiu.beznea: fixed conflict by keeping only the definition for
>>   PCIE_RESET_CONFIG_DEVICE_WAIT_MS]
> 
> I don't understand the message here. Upstream patch seems to be
> identical to this one, but context differs.

Yes, the commit d5ceb9496c565eb5763c127c6eb2d2b3068ab1df ("PCI: Add 
PCIE_RESET_CONFIG_DEVICE_WAIT_MS waiting time value") and this patch are 
identical, but, cherry-picking commit d5ceb9496c565eb5763c127c6eb2d2b3068ab1df 
on top of v5.10.249-cip69 give the following conflict:

#define PCI_VSEC_ID_INTEL_TBT   0x1234  /* Thunderbolt */ 

  

<<<<<<< HEAD 

======= 

#define PCIE_LINK_RETRAIN_TIMEOUT_MS    1000 

  

/* Power stable to PERST# inactive from PCIe card Electromechanical Spec */ 

#define PCIE_T_PVPERL_MS                100 

  

/* 

  * PCIe r6.0, sec 5.3.3.2.1 <PME Synchronization> 

  * Recommends 1ms to 10ms timeout to check L2 ready. 

  */ 

#define PCIE_PME_TO_L2_TIMEOUT_US       10000 

  

/* 

  * PCIe r6.0, sec 6.6.1 <Conventional Reset> 

  * 

  * - "With a Downstream Port that does not support Link speeds greater 

  *    than 5.0 GT/s, software must wait a minimum of 100 ms following exit 

  *    from a Conventional Reset before sending a Configuration Request to 

  *    the device immediately below that Port." 

  * 

  * - "With a Downstream Port that supports Link speeds greater than 

  *    5.0 GT/s, software must wait a minimum of 100 ms after Link training 

  *    completes before sending a Configuration Request to the device 

  *    immediately below that Port." 

  */ 

#define PCIE_RESET_CONFIG_DEVICE_WAIT_MS        100 

  

 >>>>>>> d5ceb9496c56 (PCI: Add PCIE_RESET_CONFIG_DEVICE_WAIT_MS waiting time 
value)
extern const unsigned char pcie_link_speed[]; 

extern bool pci_early_dump; 


So, I had to manually adjust it and keep only the 
PCIE_RESET_CONFIG_DEVICE_WAIT_MS define along with its documentation.

Thank you,
Claudiu


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5.10.y-cip 07/28] lib/bitmap: add bitmap_{read,write}()
  2026-03-24  9:29   ` Pavel Machek
@ 2026-03-25  8:37     ` Claudiu Beznea
  0 siblings, 0 replies; 37+ messages in thread
From: Claudiu Beznea @ 2026-03-25  8:37 UTC (permalink / raw)
  To: Pavel Machek; +Cc: nobuhiro.iwamatsu.x90, cip-dev

Hi, Pavel,

On 3/24/26 11:29, Pavel Machek wrote:
> Hi!
> 
>> From: Syed Nayyar Waris <syednwaris@gmail.com>
>>
>> commit 63c15822b8dd02a2423cfd92232245ace3f7a11b upstream.
>>
>> The two new functions allow reading/writing values of length up to
>> BITS_PER_LONG bits at arbitrary position in the bitmap.
>>
>> The code was taken from "bitops: Introduce the for_each_set_clump macro"
>> by Syed Nayyar Waris with a number of changes and simplifications:
>>   - instead of using roundup(), which adds an unnecessary dependency
>>     on <linux/math.h>, we calculate space as BITS_PER_LONG-offset;
>>   - indentation is reduced by not using else-clauses (suggested by
>>     checkpatch for bitmap_get_value());
>>   - bitmap_get_value()/bitmap_set_value() are renamed to bitmap_read()
>>     and bitmap_write();
>>   - some redundant computations are omitted.
>>
>> +++ b/include/linux/bitmap.h
>> @@ -601,6 +605,79 @@ static inline void bitmap_set_value8(unsigned long *map, unsigned long value,
>>   	map[index] |= value << offset;
>>   }
>>   
>> +/**
>> + * bitmap_read - read a value of n-bits from the memory region
>> + * @map: address to the bitmap memory region
>> + * @start: bit offset of the n-bit value
>> + * @nbits: size of value in bits, nonzero, up to BITS_PER_LONG
>> + *
>> + * Returns: value of @nbits bits located at the @start bit offset within the
>> + * @map memory region. For @nbits = 0 and @nbits > BITS_PER_LONG the return
>> + * value is undefined.
>> + */
>> +static inline unsigned long bitmap_read(const unsigned long *map,
>> +					unsigned long start,
>> +					unsigned long nbits)
>> +{
>> +	size_t index = BIT_WORD(start);
>> +	unsigned long offset = start % BITS_PER_LONG;
>> +	unsigned long space = BITS_PER_LONG - offset;
>> +	unsigned long value_low, value_high;
>> +
>> +	if (unlikely(!nbits || nbits > BITS_PER_LONG))
>> +		return 0;
> 
> If someone attempts to read more than bits_per_long, we silently give
> him 0. That sounds like recipe for hard-to-debug problem when the code
> designed for 64-bit system is ran on 32-bit.

The documentation states it explicitly:

"For @nbits = 0 and @nbits > BITS_PER_LONG the return value is undefined."

> 
> I'd expect WARN_ON here.

According to [1] the use of WARN()/WARN_ON() seems discouraged nowadays [1]


[1] https://lwn.net/Articles/969923/

> 
>> +static inline void bitmap_write(unsigned long *map, unsigned long value,
>> +				unsigned long start, unsigned long nbits)
>> +{
>> +	size_t index;
>> +	unsigned long offset;
>> +	unsigned long space;
>> +	unsigned long mask;
>> +	bool fit;
>> +
>> +	if (unlikely(!nbits || nbits > BITS_PER_LONG))
>> +		return;
> 
> And similary here.

Documentation also states "For @nbits == 0 and @nbits > BITS_PER_LONG no writes 
are performed."

Please let me know how would you like me to proceed with it.

Thank you for your review,
Claudiu


^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2026-03-25  8:37 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-11 11:03 [PATCH 5.10.y-cip 00/28] Add RZ/G3S PCIe support Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 01/28] soc: renesas: Add SYSC driver for Renesas RZ family Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 02/28] soc: renesas: rz-sysc: Move RZ/G3S SoC detection to the SYSC driver Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 03/28] mfd: syscon: Add of_syscon_register_regmap() API Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 04/28] soc: renesas: rz-sysc: Add syscon/regmap support Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 05/28] soc: renesas: rz-sysc: Populate readable_reg/writeable_reg in regmap config Claudiu
2026-03-24  9:26   ` Pavel Machek
2026-03-25  8:35     ` Claudiu Beznea
2026-03-11 11:03 ` [PATCH 5.10.y-cip 06/28] clk: renesas: r9a08g045: Add PCIe clocks and resets Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 07/28] lib/bitmap: add bitmap_{read,write}() Claudiu
2026-03-24  9:29   ` Pavel Machek
2026-03-25  8:37     ` Claudiu Beznea
2026-03-11 11:03 ` [PATCH 5.10.y-cip 08/28] genirq/msi: Silence 'set affinity failed' warning Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 09/28] PCI: Add PCIE_RESET_CONFIG_DEVICE_WAIT_MS waiting time value Claudiu
2026-03-24  9:33   ` Pavel Machek
2026-03-25  8:36     ` Claudiu Beznea
2026-03-11 11:03 ` [PATCH 5.10.y-cip 10/28] PCI: Rename PCIE_RESET_CONFIG_DEVICE_WAIT_MS to PCIE_RESET_CONFIG_WAIT_MS Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 11/28] PCI: Move link up wait time and max retries macros to pci.h Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 12/28] reset: make shared pulsed reset controls re-triggerable Claudiu
2026-03-24  9:37   ` Pavel Machek
2026-03-25  8:35     ` Claudiu Beznea
2026-03-11 11:03 ` [PATCH 5.10.y-cip 13/28] reset: Add reset_control_bulk API Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 14/28] of: Add cleanup.h based auto release via __free(device_node) markings Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 15/28] of/irq: Allow matching of an interrupt-map local to an interrupt controller Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 16/28] of/irq: Update the out_irq->np before returning success Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 17/28] dt-bindings: PCI: Add Renesas RZ/G3S PCIe controller binding Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 18/28] PCI: Add Renesas RZ/G3S host controller driver Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 19/28] PCI: rzg3s-host: Initialize MSI status bitmap before use Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 20/28] PCI: rzg3s-host: Use pci_generic_config_write() for the root bus Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 21/28] PCI: rzg3s-host: Drop the lock on RZG3S_PCI_MSIRS and RZG3S_PCI_PINTRCVIS Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 22/28] PCI: rzg3s-host: Fix device node reference leak in rzg3s_pcie_host_parse_port() Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 23/28] arm64: dts: renesas: r9a08g045: Enable SYS node Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 24/28] arm64: dts: renesas: r9a08g045: Use syscon compatible for the system controller Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 25/28] arm64: dts: renesas: r9a08g045: Add PCIe node Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 26/28] arm64: dts: renesas: rzg3s-smarc-som: Add PCIe reference clock Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 27/28] arm64: dts: renesas: rzg3s-smarc: Enable PCIe Claudiu
2026-03-11 11:03 ` [PATCH 5.10.y-cip 28/28] arm64: defconfig: Enable PCIe for the Renesas RZ/G3S SoC Claudiu

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