linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/9] PCI: rzg3s-host: Add PCIe driver for Renesas RZ/G3S SoC
@ 2025-07-04 16:14 Claudiu
  2025-07-04 16:14 ` [PATCH v3 1/9] soc: renesas: rz-sysc: Add syscon/regmap support Claudiu
                   ` (9 more replies)
  0 siblings, 10 replies; 47+ messages in thread
From: Claudiu @ 2025-07-04 16:14 UTC (permalink / raw)
  To: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou
  Cc: claudiu.beznea, linux-pci, linux-renesas-soc, devicetree,
	linux-kernel, linux-arm-kernel, linux-clk, Claudiu Beznea

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

Hi,

Series adds a PCIe driver for the Renesas RZ/G3S SoC.
It is split as follows:
- patch 1/9:		updates the max register offset for RZ/G3S SYSC;
			this is necessary as the PCIe need to setup the
			SYSC for proper functioning
- patch 2/9:		adds clocks and resets support for the PCIe IP
- patch 3/9:		fix the legacy interrupt request failure
- patches 4-5/9:	add PCIe support for the RZ/G3S SoC
- patches 6-9/9:	add device tree support and defconfig flag

Please provide your feedback.

Merge strategy, if any:
- patches 1-2,6-9/9 can go through the Renesas tree
- patches 3-5/9 can go through the PCI tree

Thank you,
Claudiu Beznea

Changes in v3:
- added patch "PCI: of_property: Restore the arguments of the next level parent"
  to fix the legacy interrupt request
- addressed review comments
- per-patch changes are described in each individual patch

Changes in v2:
- dropped "of/irq: Export of_irq_count()" as it is not needed anymore
  in this version
- added "arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe"
  to reflect the board specific memory constraints
- addressed review comments
- updated patch "soc: renesas: rz-sysc: Add syscon/regmap support"
- per-patch changes are described in each individual patch


Claudiu Beznea (8):
  clk: renesas: r9a08g045: Add clocks and resets support for PCIe
  PCI: of_property: Restore the arguments of the next level parent
  dt-bindings: PCI: renesas,r9a08g045s33-pcie: Add documentation for the
    PCIe IP on Renesas RZ/G3S
  PCI: rzg3s-host: Add Initial PCIe Host Driver for Renesas RZ/G3S SoC
  arm64: dts: renesas: r9a08g045s33: Add PCIe node
  arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe
  arm64: dts: renesas: rzg3s-smarc: Enable PCIe
  arm64: defconfig: Enable PCIe for the Renesas RZ/G3S SoC

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

 .../pci/renesas,r9a08g045s33-pcie.yaml        |  202 ++
 MAINTAINERS                                   |    8 +
 arch/arm64/boot/dts/renesas/r9a08g045s33.dtsi |   60 +
 .../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/pci/controller/Kconfig                |    7 +
 drivers/pci/controller/Makefile               |    1 +
 drivers/pci/controller/pcie-rzg3s-host.c      | 1715 +++++++++++++++++
 drivers/pci/of_property.c                     |    8 +
 drivers/soc/renesas/Kconfig                   |    1 +
 drivers/soc/renesas/r9a08g045-sysc.c          |   10 +
 drivers/soc/renesas/r9a09g047-sys.c           |   10 +
 drivers/soc/renesas/r9a09g057-sys.c           |   10 +
 drivers/soc/renesas/rz-sysc.c                 |   17 +-
 drivers/soc/renesas/rz-sysc.h                 |    3 +
 17 files changed, 2087 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/pci/renesas,r9a08g045s33-pcie.yaml
 create mode 100644 drivers/pci/controller/pcie-rzg3s-host.c

-- 
2.43.0



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

* [PATCH v3 1/9] soc: renesas: rz-sysc: Add syscon/regmap support
  2025-07-04 16:14 [PATCH v3 0/9] PCI: rzg3s-host: Add PCIe driver for Renesas RZ/G3S SoC Claudiu
@ 2025-07-04 16:14 ` Claudiu
  2025-07-04 16:14 ` [PATCH v3 2/9] clk: renesas: r9a08g045: Add clocks and resets support for PCIe Claudiu
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 47+ messages in thread
From: Claudiu @ 2025-07-04 16:14 UTC (permalink / raw)
  To: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou
  Cc: claudiu.beznea, linux-pci, linux-renesas-soc, devicetree,
	linux-kernel, linux-arm-kernel, linux-clk, John Madieu,
	Wolfram Sang, Claudiu Beznea

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

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,
add register a custom regmap configuration.

Signed-off-by: John Madieu <john.madieu.xa@bp.renesas.com>
Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
[claudiu.beznea:
 - s/rzg3e_sysc_regmap/rzv2h_sysc_regmap in RZ/V2H sysc
   file
 - do not check the match->data validity in rz_sysc_probe() as it is
   always valid
 - register the regmap if data->regmap_cfg is valid]
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v3:
- collected tags

Changes in v2:
- picked the latest version from John after he addressed the review
  comments received at [1];
- I adjusted as specified in the SoB area

[1] https://lore.kernel.org/all/20250330214945.185725-2-john.madieu.xa@bp.renesas.com/

 drivers/soc/renesas/Kconfig          |  1 +
 drivers/soc/renesas/r9a08g045-sysc.c | 10 ++++++++++
 drivers/soc/renesas/r9a09g047-sys.c  | 10 ++++++++++
 drivers/soc/renesas/r9a09g057-sys.c  | 10 ++++++++++
 drivers/soc/renesas/rz-sysc.c        | 17 ++++++++++++++++-
 drivers/soc/renesas/rz-sysc.h        |  3 +++
 6 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig
index 1930a12b8fa7..58a4ab2643d6 100644
--- a/drivers/soc/renesas/Kconfig
+++ b/drivers/soc/renesas/Kconfig
@@ -452,6 +452,7 @@ config RST_RCAR
 
 config SYSC_RZ
 	bool "System controller for RZ SoCs" if COMPILE_TEST
+	select MFD_SYSCON
 
 config SYSC_R9A08G045
 	bool "Renesas System controller support for R9A08G045 (RZ/G3S)" if COMPILE_TEST
diff --git a/drivers/soc/renesas/r9a08g045-sysc.c b/drivers/soc/renesas/r9a08g045-sysc.c
index f4db1431e036..0ef6df77e25f 100644
--- a/drivers/soc/renesas/r9a08g045-sysc.c
+++ b/drivers/soc/renesas/r9a08g045-sysc.c
@@ -18,6 +18,16 @@ static const struct rz_sysc_soc_id_init_data rzg3s_sysc_soc_id_init_data __initc
 	.specific_id_mask = GENMASK(27, 0),
 };
 
+static const struct regmap_config rzg3s_sysc_regmap __initconst = {
+	.name = "rzg3s_sysc_regs",
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.fast_io = true,
+	.max_register = 0xe20,
+};
+
 const struct rz_sysc_init_data rzg3s_sysc_init_data __initconst = {
 	.soc_id_init_data = &rzg3s_sysc_soc_id_init_data,
+	.regmap_cfg = &rzg3s_sysc_regmap,
 };
diff --git a/drivers/soc/renesas/r9a09g047-sys.c b/drivers/soc/renesas/r9a09g047-sys.c
index cd2eb7782cfe..a3acf6dd2867 100644
--- a/drivers/soc/renesas/r9a09g047-sys.c
+++ b/drivers/soc/renesas/r9a09g047-sys.c
@@ -62,6 +62,16 @@ static const struct rz_sysc_soc_id_init_data rzg3e_sys_soc_id_init_data __initco
 	.print_id = rzg3e_sys_print_id,
 };
 
+static const struct regmap_config rzg3e_sysc_regmap __initconst = {
+	.name = "rzg3e_sysc_regs",
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.fast_io = true,
+	.max_register = 0x170c,
+};
+
 const struct rz_sysc_init_data rzg3e_sys_init_data = {
 	.soc_id_init_data = &rzg3e_sys_soc_id_init_data,
+	.regmap_cfg = &rzg3e_sysc_regmap,
 };
diff --git a/drivers/soc/renesas/r9a09g057-sys.c b/drivers/soc/renesas/r9a09g057-sys.c
index 4c21cc29edbc..c26821636dce 100644
--- a/drivers/soc/renesas/r9a09g057-sys.c
+++ b/drivers/soc/renesas/r9a09g057-sys.c
@@ -62,6 +62,16 @@ static const struct rz_sysc_soc_id_init_data rzv2h_sys_soc_id_init_data __initco
 	.print_id = rzv2h_sys_print_id,
 };
 
+static const struct regmap_config rzv2h_sysc_regmap __initconst = {
+	.name = "rzv2h_sysc_regs",
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.fast_io = true,
+	.max_register = 0x170c,
+};
+
 const struct rz_sysc_init_data rzv2h_sys_init_data = {
 	.soc_id_init_data = &rzv2h_sys_soc_id_init_data,
+	.regmap_cfg = &rzv2h_sysc_regmap,
 };
diff --git a/drivers/soc/renesas/rz-sysc.c b/drivers/soc/renesas/rz-sysc.c
index ffa65fb4dade..70556a2f55e6 100644
--- a/drivers/soc/renesas/rz-sysc.c
+++ b/drivers/soc/renesas/rz-sysc.c
@@ -6,8 +6,10 @@
  */
 
 #include <linux/io.h>
+#include <linux/mfd/syscon.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/sys_soc.h>
 
 #include "rz-sysc.h"
@@ -100,14 +102,19 @@ 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;
 
 	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;
@@ -117,7 +124,15 @@ 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 || !data->regmap_cfg)
+		return ret;
+
+	regmap = devm_regmap_init_mmio(dev, sysc->base, data->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 56bc047a1bff..447008140634 100644
--- a/drivers/soc/renesas/rz-sysc.h
+++ b/drivers/soc/renesas/rz-sysc.h
@@ -9,6 +9,7 @@
 #define __SOC_RENESAS_RZ_SYSC_H__
 
 #include <linux/device.h>
+#include <linux/regmap.h>
 #include <linux/sys_soc.h>
 #include <linux/types.h>
 
@@ -34,9 +35,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
+ * @regmap_cfg: SoC-specific regmap config
  */
 struct rz_sysc_init_data {
 	const struct rz_sysc_soc_id_init_data *soc_id_init_data;
+	const struct regmap_config *regmap_cfg;
 };
 
 extern const struct rz_sysc_init_data rzg3e_sys_init_data;
-- 
2.43.0



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

* [PATCH v3 2/9] clk: renesas: r9a08g045: Add clocks and resets support for PCIe
  2025-07-04 16:14 [PATCH v3 0/9] PCI: rzg3s-host: Add PCIe driver for Renesas RZ/G3S SoC Claudiu
  2025-07-04 16:14 ` [PATCH v3 1/9] soc: renesas: rz-sysc: Add syscon/regmap support Claudiu
@ 2025-07-04 16:14 ` Claudiu
  2025-08-04 10:25   ` Geert Uytterhoeven
  2025-07-04 16:14 ` [PATCH v3 3/9] PCI: of_property: Restore the arguments of the next level parent Claudiu
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 47+ messages in thread
From: Claudiu @ 2025-07-04 16:14 UTC (permalink / raw)
  To: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou
  Cc: claudiu.beznea, linux-pci, linux-renesas-soc, devicetree,
	linux-kernel, linux-arm-kernel, linux-clk, Claudiu Beznea,
	Wolfram Sang

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

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>
---

Changes in v3:
- collected tags
- dropped the power domain support and added MSTOP as power domain
  code is not available anymore in the current linux-next
- adjusted the patch title and description

Changes in v2:
- none

 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 405907925bb7..4a6632ea22cb 100644
--- a/drivers/clk/renesas/r9a08g045-cpg.c
+++ b/drivers/clk/renesas/r9a08g045-cpg.c
@@ -289,6 +289,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_clk1pm",		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))),
 };
@@ -329,6 +333,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),
 };
 
@@ -340,6 +351,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,
@@ -356,6 +371,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] 47+ messages in thread

* [PATCH v3 3/9] PCI: of_property: Restore the arguments of the next level parent
  2025-07-04 16:14 [PATCH v3 0/9] PCI: rzg3s-host: Add PCIe driver for Renesas RZ/G3S SoC Claudiu
  2025-07-04 16:14 ` [PATCH v3 1/9] soc: renesas: rz-sysc: Add syscon/regmap support Claudiu
  2025-07-04 16:14 ` [PATCH v3 2/9] clk: renesas: r9a08g045: Add clocks and resets support for PCIe Claudiu
@ 2025-07-04 16:14 ` Claudiu
  2025-08-20 17:47   ` Manivannan Sadhasivam
  2025-07-04 16:14 ` [PATCH v3 4/9] dt-bindings: PCI: renesas,r9a08g045s33-pcie: Add documentation for the PCIe IP on Renesas RZ/G3S Claudiu
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 47+ messages in thread
From: Claudiu @ 2025-07-04 16:14 UTC (permalink / raw)
  To: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou
  Cc: claudiu.beznea, linux-pci, linux-renesas-soc, devicetree,
	linux-kernel, linux-arm-kernel, linux-clk, Claudiu Beznea

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

of_pci_make_dev_node() creates a device tree node for the PCIe bridge it
detects. The node name follows the format: pci_type@pci_slot,pci_func. If
such a node already exists in the current device tree, a new one is not
created.

When the node is created, its contents are populated with information from
the parent node. In the case of root complex nodes described in the device
tree, the created node duplicates the interrupt-map property. However, the
duplicated interrupt-map property does not correctly point to the next
interrupt controller.

For example, in the case of the Renesas RZ/G3S SoC, the resulting device
tree node is as follows (only relevant DT properties are shown):

pcie@11e40000 {

    // ...

    interrupt-map = <0x00 0x00 0x00 0x01 0x1f 0x00 0x00 0x00 0x00
                     0x00 0x00 0x00 0x02 0x1f 0x00 0x00 0x00 0x01
                     0x00 0x00 0x00 0x03 0x1f 0x00 0x00 0x00 0x02
                     0x00 0x00 0x00 0x04 0x1f 0x00 0x00 0x00 0x03>;
    interrupt-map-mask = <0x00 0x00 0x00 0x07>;
    interrupt-controller;
    #interrupt-cells = <0x01>;

    #address-cells = <0x03>;
    #size-cells = <0x02>;

    phandle = <0x1f>;

    // ...

    pci@0,0 {
        reg = <0x00 0x00 0x00 0x00 0x00>;
        interrupt-map = <0x10000 0x00 0x00 0x01 0x1f 0x00 0x11e40000 0x00 0x00
                         0x10000 0x00 0x00 0x02 0x1f 0x00 0x11e40000 0x00 0x01
                         0x10000 0x00 0x00 0x03 0x1f 0x00 0x11e40000 0x00 0x02
                         0x10000 0x00 0x00 0x04 0x1f 0x00 0x11e40000 0x00 0x03>;
        interrupt-map-mask = <0xffff00 0x00 0x00 0x07>;
        #interrupt-cells = <0x01>;

        #address-cells = <0x03>;
        #size-cells = <0x02>;

        // ...
    };
};

With this pci@0,0 node, the interrupt-map parsing code behaves as follows:

When a PCIe endpoint is enumerated and it requests to map a legacy
interrupt, of_irq_parse_raw() is called requesting the interrupt from
pci@0,0. If INTA is requested, of_irq_parse_raw() first matches:

interrupt-map = <0x10000 0x00 0x00 0x01 0x1f 0x00 0x11e40000 0x00 0x00>

from the pci@0,0 node. It then follows the phandle 0x1f to the interrupt
parent, looking for a mapping for interrupt ID 0x00
(0x00 0x11e40000 0x00 0x00). However, the root complex node does not
provide this mapping in its interrupt-map property, causing the interrupt
request to fail.

To avoid this, in the interrupt-map property of the nodes generated by
of_pci_make_dev_node() map legacy interrupts to entries that are valid in
the next level interrupt controller in the interrupt mapping tree.

With this, the generated pci@0,0 node and its parent look as follows:

pcie@11e40000 {
    // ...

    interrupt-map = <0x00 0x00 0x00 0x01 0x1f 0x00 0x00 0x00 0x00
                     0x00 0x00 0x00 0x02 0x1f 0x00 0x00 0x00 0x01
                     0x00 0x00 0x00 0x03 0x1f 0x00 0x00 0x00 0x02
                     0x00 0x00 0x00 0x04 0x1f 0x00 0x00 0x00 0x03>;
    interrupt-map-mask = <0x00 0x00 0x00 0x07>;
    interrupt-controller;
    #interrupt-cells = <0x01>;

    #address-cells = <0x03>;
    #size-cells = <0x02>;

    phandle = <0x1f>;

    // ...

    pci@0,0 {
        reg = <0x00 0x00 0x00 0x00 0x00>;
        interrupt-map = <0x10000 0x00 0x00 0x01 0x1f 0x00 0x11e40000 0x00 0x01
                         0x10000 0x00 0x00 0x02 0x1f 0x00 0x11e40000 0x00 0x02
                         0x10000 0x00 0x00 0x03 0x1f 0x00 0x11e40000 0x00 0x03
                         0x10000 0x00 0x00 0x04 0x1f 0x00 0x11e40000 0x00 0x04>;
        interrupt-map-mask = <0xffff00 0x00 0x00 0x07>;
        #interrupt-cells = <0x01>;

        #address-cells = <0x03>;
        #size-cells = <0x02>;
    };
};

Fixes: 407d1a51921e ("PCI: Create device tree node for bridge")
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v3:
- none; this patch is new

 drivers/pci/of_property.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/pci/of_property.c b/drivers/pci/of_property.c
index 506fcd507113..8dfed096326f 100644
--- a/drivers/pci/of_property.c
+++ b/drivers/pci/of_property.c
@@ -243,6 +243,14 @@ static int of_pci_prop_intr_map(struct pci_dev *pdev, struct of_changeset *ocs,
 		}
 		of_property_read_u32(out_irq[i].np, "#address-cells",
 				     &addr_sz[i]);
+
+		/*
+		 * Restore the arguments of the next level parent if a map
+		 * was found.
+		 */
+		out_irq[i].np = pnode;
+		out_irq[i].args_count = 1;
+		out_irq[i].args[0] = pin;
 	}
 
 	list_for_each_entry(child, &pdev->subordinate->devices, bus_list) {
-- 
2.43.0



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

* [PATCH v3 4/9] dt-bindings: PCI: renesas,r9a08g045s33-pcie: Add documentation for the PCIe IP on Renesas RZ/G3S
  2025-07-04 16:14 [PATCH v3 0/9] PCI: rzg3s-host: Add PCIe driver for Renesas RZ/G3S SoC Claudiu
                   ` (2 preceding siblings ...)
  2025-07-04 16:14 ` [PATCH v3 3/9] PCI: of_property: Restore the arguments of the next level parent Claudiu
@ 2025-07-04 16:14 ` Claudiu
  2025-07-08 16:34   ` Bjorn Helgaas
  2025-07-04 16:14 ` [PATCH v3 5/9] PCI: rzg3s-host: Add Initial PCIe Host Driver for Renesas RZ/G3S SoC Claudiu
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 47+ messages in thread
From: Claudiu @ 2025-07-04 16:14 UTC (permalink / raw)
  To: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou
  Cc: claudiu.beznea, linux-pci, linux-renesas-soc, devicetree,
	linux-kernel, linux-arm-kernel, linux-clk, Claudiu Beznea,
	Wolfram Sang

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

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 documentation for it.

Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v3:
- collected tags
- updated the flags of ranges property from example

Changes in v2:
- update the interrupt names by dropping "int" and "rc" string; due
  to this the patch description was adjusted
- added "interrupt-controller" and made it mandatory
- s/clkl1pm/pm/g
- dropped the legacy-interrupt-controller node; with this the gic
  interrupt controller node was dropped as well as it is not needed
  anymore
- updated interrupt-map in example and added interrupt-controller
- added clock-names as required property as the pm clock is not
  handled though PM domains; this will allow the driver to have
  the option to request the pm clock by its name when implementation
  will be adjusted to used the pm clock
- adjusted the size of dma-ranges to reflect the usage on
  SMARC module board
- moved "renesas,sysc" at the end of the node in example to align
  with dts coding style

 .../pci/renesas,r9a08g045s33-pcie.yaml        | 202 ++++++++++++++++++
 1 file changed, 202 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/renesas,r9a08g045s33-pcie.yaml

diff --git a/Documentation/devicetree/bindings/pci/renesas,r9a08g045s33-pcie.yaml b/Documentation/devicetree/bindings/pci/renesas,r9a08g045s33-pcie.yaml
new file mode 100644
index 000000000000..42a9494c96c0
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/renesas,r9a08g045s33-pcie.yaml
@@ -0,0 +1,202 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pci/renesas,r9a08g045s33-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,r9a08g045s33-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 phandle
+    $ref: /schemas/types.yaml#/definitions/phandle
+
+  vendor-id:
+    const: 0x1912
+
+  device-id:
+    const: 0x0033
+
+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
+  - vendor-id
+  - device-id
+
+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,r9a08g045s33-pcie";
+            reg = <0 0x11e40000 0 0x10000>;
+            ranges = <0x02000000 0 0x30000000 0 0x30000000 0 0x8000000>;
+            dma-ranges = <0x42000000 0 0x48000000 0 0x48000000 0 0x38000000>;
+            bus-range = <0x0 0xff>;
+            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";
+            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>, /* INT A */
+                            <0 0 0 2 &pcie 0 0 0 1>, /* INT B */
+                            <0 0 0 3 &pcie 0 0 0 2>, /* INT C */
+                            <0 0 0 4 &pcie 0 0 0 3>; /* INT D */
+            device_type = "pci";
+            num-lanes = <1>;
+            #address-cells = <3>;
+            #size-cells = <2>;
+            power-domains = <&cpg>;
+            vendor-id = <0x1912>;
+            device-id = <0x0033>;
+            renesas,sysc = <&sysc>;
+        };
+    };
+
+...
-- 
2.43.0



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

* [PATCH v3 5/9] PCI: rzg3s-host: Add Initial PCIe Host Driver for Renesas RZ/G3S SoC
  2025-07-04 16:14 [PATCH v3 0/9] PCI: rzg3s-host: Add PCIe driver for Renesas RZ/G3S SoC Claudiu
                   ` (3 preceding siblings ...)
  2025-07-04 16:14 ` [PATCH v3 4/9] dt-bindings: PCI: renesas,r9a08g045s33-pcie: Add documentation for the PCIe IP on Renesas RZ/G3S Claudiu
@ 2025-07-04 16:14 ` Claudiu
  2025-07-08 19:24   ` Bjorn Helgaas
  2025-08-30  6:59   ` Manivannan Sadhasivam
  2025-07-04 16:14 ` [PATCH v3 6/9] arm64: dts: renesas: r9a08g045s33: Add PCIe node Claudiu
                   ` (4 subsequent siblings)
  9 siblings, 2 replies; 47+ messages in thread
From: Claudiu @ 2025-07-04 16:14 UTC (permalink / raw)
  To: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou
  Cc: claudiu.beznea, linux-pci, linux-renesas-soc, devicetree,
	linux-kernel, linux-arm-kernel, linux-clk, Claudiu Beznea,
	Wolfram Sang

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

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

Link: https://www.renesas.com/en/products/rz-g3s?queryID=695cc067c2d89e3f271d43656ede4d12
Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v3:
- updated patch description with link to the hardware manual and steps
  to access it
- included <linux/bitfields.h> to solve compilation errors
- used devm_mutex_init()
- used SZ_4K instead of 4096
- dropped PCIe register defines and used the ones from
  include/uapi/linux/pci_regs.h; added RZG3S_PCI_CFG_PCIEC as the starting
  offset of the capabilities to be used before the host bridge is
  registered
- added blank lines around registers and bitfields defines
- kept the defines for bitfies in order (from MSB to LSB)
- dropped timeout defines (except RZG3S_REQ_ISSUE_TIMEOUT_US) and
  used the ones from ../pci.h
- dropped rzg3s_pcie_link_speed and used defines from 
  include/uapi/linux/pci_regs.h
- in rzg3s_pcie_child_write() call directly rzg3s_pcie_child_write_conf()
  if size is 4 and print the warning message on in the other cases
- return NULL in rzg3s_pcie_child_map_bus() and added a comment about it
- in rzg3s_pcie_root_write() and rzg3s_soc_pcie_init_phy() added a comment
  about the setting done on RZG3S_PCI_PERM register
- register rzg3s_pcie_msi_free_domains(), rzg3s_pcie_msi_teardown(),
  rzg3s_pcie_intx_teardown() as devm action or reset functions
- used irq_domain_create_linear() for intx domain
- added the rzg3s_pcie_power_resets_deassert() helper to de-assert the
  power domain and wait before doing it
- wait PCIE_RESET_CONFIG_WAIT_MS before registering the host
- made rzg3s_soc_power_resets[] and rzg3s_soc_cfg_resets[] static
- added suppress_bind_attrs = true
- collected tags

Changes in v2:
- dropped the references to other RZ SoCs from patch description
- dropped the dot at the end of single line comments that are not a
  sentence
- as a result of v2 rework removed unused macros and definitions
  (e.g. RZG3S_PCI_REQISS_TR_TP1_RD, RZG3S_PCI_REQISS_TR_TP1_WR,
  enum rzg3s_pcie_cfg_access_type)
- dropped driver specific defines that are for generic PCI
  register offsets and used the generic ones
- updated the value of RZG3S_PCI_MSI_INT_NR as on RZ/G3S there
  are no more than 32 MSIs (v1 value was due to mistake in the
  HW manual)
- added timeout macros to be used by read_poll_timeout() specific
  functions
- re-worked the reset handling part by using reset subsystem specific
  functions only; with this the struct rzg3s_pcie_soc_data was
  added; reference to PHY initialization function was added to this
  structure as well
- dropped devres_group_id as the issue it tried to address will
  now be fixed in platform bus code (v2 posted [2])
- use 80 columns alignment
- updated function name in the idea of using names similar to
  what is used in other drivers
- added rzg3s_pcie_root_ops and rzg3s_pcie_child_ops and populate
  bridge->ops, bridge->child_ops with it; from probe:
+	bridge->ops = &rzg3s_pcie_root_ops;
+	bridge->child_ops = &rzg3s_pcie_child_ops;
- print a warning for 32 bit accesses (based on the value of
  bus->unsafe_warn as done in the common code)
- dropped dev_dbg() in read/write functions
- added HW manual revision identifier in comments that points to the
  statements from manual
- reworked the rzg3s_pcie_intx_setup() as the legacy interrupt DT
  node is not used anymore
- in rzg3s_pcie_config_init() do not hardcode anymore the
  primary bus, secondary bus, subordinate bus but get this information
  from device tree and update HW registers accordingly
- dropped rzg3s_pcie_remove() and added rzg3s_pcie_host_remove_action()
  to be used as a devm action or reset function
- s/rzg3s_pcie_suspend/rzg3s_pcie_suspend_noirq,
  s/rzg3s_pcie_resume/rzg3s_pcie_resume_noirq
- dropped DEFINE_NOIRQ_DEV_PM_OPS()
- updated driver name (rzg3s-pcie-host) to reflect it is for RZ/G3S 

[2] https://lore.kernel.org/all/20250526122054.65532-2-claudiu.beznea.uj@bp.renesas.com

 MAINTAINERS                              |    8 +
 drivers/pci/controller/Kconfig           |    7 +
 drivers/pci/controller/Makefile          |    1 +
 drivers/pci/controller/pcie-rzg3s-host.c | 1715 ++++++++++++++++++++++
 4 files changed, 1731 insertions(+)
 create mode 100644 drivers/pci/controller/pcie-rzg3s-host.c

diff --git a/MAINTAINERS b/MAINTAINERS
index fcc77c93f8db..31ef76503e17 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19435,6 +19435,14 @@ S:	Maintained
 F:	drivers/pci/controller/dwc/pcie-qcom-common.c
 F:	drivers/pci/controller/dwc/pcie-qcom.c
 
+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,r9a08g045s33-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 886f6f43a895..76fa5f330105 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -258,6 +258,13 @@ config PCI_RCAR_GEN2
 	  There are 3 internal PCI controllers available with a single
 	  built-in EHCI/OHCI host controller present on each one.
 
+config PCIE_RENESAS_RZG3S_HOST
+	tristate "Renesas RZ/G3S PCIe host controller"
+	depends on ARCH_RENESAS || COMPILE_TEST
+	select MFD_SYSCON
+	help
+	  Say Y here if you want PCIe host controller support on Renesas RZ/G3S SoC.
+
 config PCIE_ROCKCHIP
 	bool
 	depends on PCI
diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
index 038ccbd9e3ba..229929a945c2 100644
--- a/drivers/pci/controller/Makefile
+++ b/drivers/pci/controller/Makefile
@@ -10,6 +10,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_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.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..9b5a516de55d
--- /dev/null
+++ b/drivers/pci/controller/pcie-rzg3s-host.c
@@ -0,0 +1,1715 @@
+// 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/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_REQ_ISSUE		BIT(0)
+
+#define RZG3S_PCI_MSIRCVWADRL			0x100
+#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_MSIRCVWMSKU			0x10c
+
+#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_AMEIE				0x210
+#define RZG3S_PCI_AMEIS				0x214
+#define RZG3S_PCI_ASEIE1			0x220
+#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_STATE_RX_DETECT	GENMASK(15, 8)
+#define RZG3S_PCI_PCSTAT2_SDRIRE		GENMASK(7, 0)
+
+#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
+ */
+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;
+};
+
+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_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
+ * @hw_lock: lock for access to the HW resources
+ * @intx_irqs: INTx interrupts
+ * @vendor_id: Vendor ID
+ * @device_id: Device ID
+ */
+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;
+	raw_spinlock_t hw_lock;
+	int intx_irqs[PCI_NUM_INTX];
+	u32 vendor_id;
+	u32 device_id;
+};
+
+#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(base + offset);
+	tmp &= ~mask;
+	tmp |= val & mask;
+	writel(tmp, base + offset);
+}
+
+static bool 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);
+
+	return !!ret || (val & RZG3S_PCI_REQISS_MOR_STATUS);
+}
+
+static int rzg3s_pcie_child_read_conf(struct rzg3s_pcie_host *host,
+				      struct pci_bus *bus,
+				      unsigned int devfn, int where,
+				      u32 *data)
+{
+	int ret;
+
+	bus->ops->map_bus(bus, devfn, where);
+
+	/* Set the type of request */
+	writel(RZG3S_PCI_REQISS_TR_TP0_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(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)
+{
+	int ret;
+
+	bus->ops->map_bus(bus, devfn, where);
+
+	/* Set the write data  */
+	writel(0, host->axi + RZG3S_PCI_REQDATA(0));
+	writel(0, host->axi + RZG3S_PCI_REQDATA(1));
+	writel(data, host->axi + RZG3S_PCI_REQDATA(2));
+
+	/* Set the type of request */
+	writel(RZG3S_PCI_REQISS_TR_TP0_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 void __iomem *rzg3s_pcie_child_map_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(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(RZG3S_PCI_REQBE_BYTE_EN, host->axi + RZG3S_PCI_REQBE);
+
+	/*
+	 * rzg3s_pcie_child_map_bus() is used to configure the controller before
+	 * executing requests. It is called only within this driver and not
+	 * through subsystem calls. Since it does not return an address that
+	 * needs to be used later, return NULL.
+	 */
+	return NULL;
+}
+
+static struct pci_ops rzg3s_pcie_child_ops = {
+	.read		= rzg3s_pcie_child_read,
+	.write		= rzg3s_pcie_child_write,
+	.map_bus	= rzg3s_pcie_child_map_bus,
+};
+
+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;
+}
+
+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;
+
+	/* Enable access control to the CFGU */
+	writel(RZG3S_PCI_PERM_CFG_HWINIT_EN, host->axi + RZG3S_PCI_PERM);
+
+	pci_generic_config_write(bus, devfn, where, size, val);
+
+	/* Disable access control to the CFGU */
+	writel(0, host->axi + RZG3S_PCI_PERM);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+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];
+
+	chained_irq_enter(chip, desc);
+	generic_handle_domain_irq(host->intx_domain, intx);
+	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;
+
+	status = readl(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 (u8 reg_id = 0; reg_id < regs; reg_id++) {
+		status = readl(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) {
+		int ret;
+
+		ret = generic_handle_domain_irq(msi->domain->parent, bit);
+		if (ret) {
+			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(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(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 drop_mask = RZG3S_PCI_MSIRCVWADRL_ENA |
+			RZG3S_PCI_MSIRCVWADRL_MSG_DATA_ENA;
+	u32 lo, hi;
+
+	/*
+	 * Enable and msg data enable bits are part of the address lo. Drop
+	 * them.
+	 */
+	lo = readl(host->axi + RZG3S_PCI_MSIRCVWADRL) & ~drop_mask;
+	hi = readl(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;
+	int hwirq;
+
+	scoped_guard(mutex, &msi->map_lock) {
+		hwirq = bitmap_find_free_region(msi->map, RZG3S_PCI_MSI_INT_NR,
+						order_base_2(nr_irqs));
+	}
+
+	if (hwirq < 0)
+		return -ENOSPC;
+
+	for (unsigned int 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 MSI 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;
+
+	/*
+	 * Set MSI window size. HW will set the window to
+	 * RZG3S_PCI_MSI_INT_NR * 4 bytes.
+	 */
+	writel(RZG3S_PCI_MSI_INT_NR - 1, host->axi + RZG3S_PCI_MSIRCVWMSKL);
+
+	/* Set MSI window address and enable MSI window */
+	writel(upper_32_bits(msi->window_base),
+	       host->axi + RZG3S_PCI_MSIRCVWADRU);
+	writel(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 (u8 reg_id = 0; reg_id < regs; reg_id++) {
+		writel(RZG3S_PCI_MSIRE_ENA,
+		       host->axi + RZG3S_PCI_MSIRE(reg_id));
+	}
+
+	/* Enable message receive interrupts */
+	writel(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 need to be within any AXI window. Find
+	 * an 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(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(host->axi + RZG3S_PCI_AWBASEU(id));
+		base = baseu << 32 | basel;
+
+		maskl = readl(host->axi + RZG3S_PCI_AWMASKL(id));
+		masku = readl(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 need to 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_teardown(void *data)
+{
+	u8 regs = RZG3S_PCI_MSI_INT_NR / RZG3S_PCI_MSI_INT_PER_REG;
+	size_t size = RZG3S_PCI_MSI_INT_NR * sizeof(u32);
+	struct rzg3s_pcie_host *host = data;
+	struct rzg3s_pcie_msi *msi = &host->msi;
+
+	/* 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 (u8 reg_id = 0; reg_id < regs; reg_id++)
+		writel(0, host->axi + RZG3S_PCI_MSIRE(reg_id));
+
+	/* Disable MSI window */
+	writel(0, host->axi + RZG3S_PCI_MSIRCVWADRL);
+
+	/* 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_free_domains(void *data)
+{
+	struct irq_domain *domain = data;
+	struct irq_domain *parent = domain->parent;
+
+	irq_domain_remove(domain);
+	irq_domain_remove(parent);
+}
+
+static int rzg3s_pcie_msi_enable(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;
+	const char *devname;
+	int irq, ret;
+
+	ret = devm_mutex_init(dev, &msi->map_lock);
+	if (ret)
+		return ret;
+
+	irq = platform_get_irq_byname(pdev, "msi");
+	if (irq < 0)
+		return dev_err_probe(dev, irq ? irq : -EINVAL,
+				     "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;
+
+	ret = devm_add_action_or_reset(dev, rzg3s_pcie_msi_free_domains, msi->domain);
+	if (ret)
+		return ret;
+
+	ret = devm_request_irq(dev, irq, rzg3s_pcie_msi_irq, 0, devname, host);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to request IRQ: %d\n", ret);
+
+	ret = rzg3s_pcie_msi_setup(host);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to setup MSI!\n");
+
+	return devm_add_action_or_reset(dev, rzg3s_pcie_msi_teardown, host);
+}
+
+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 void rzg3s_pcie_intx_teardown(void *data)
+{
+	struct rzg3s_pcie_host *host = data;
+
+	irq_domain_remove(host->intx_domain);
+}
+
+static int rzg3s_pcie_intx_setup(struct rzg3s_pcie_host *host)
+{
+	struct device *dev = host->dev;
+
+	for (int i = 0; i < PCI_NUM_INTX; i++) {
+		struct platform_device *pdev = to_platform_device(dev);
+		char irq_name[5] = {0};
+		int irq;
+
+		scnprintf(irq_name, ARRAY_SIZE(irq_name), "int%c", 97 + 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",
+					     65 + 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(of_fwnode_handle(dev->of_node),
+						     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);
+
+	return devm_add_action_or_reset(dev, rzg3s_pcie_intx_teardown, host);
+}
+
+static int rzg3s_pcie_set_max_link_speed(struct rzg3s_pcie_host *host)
+{
+	u32 cs2, link_speed, remote_supported_link_speeds, tmp;
+	u32 pcie_cap = RZG3S_PCI_CFG_PCIEC;
+	u8 ltssm_state_l0 = 0xc;
+	u16 lcs;
+	int ret;
+
+	/*
+	 * 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 link training and status state machine in the PCIe Core
+	 * Link is 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,
+				 PCIE_LINK_WAIT_SLEEP_MS *
+				 PCIE_LINK_WAIT_MAX_RETRIES * MILLI);
+	if (ret) {
+		dev_dbg(host->dev,
+			"Could not set max link speed! LTSSM not in L0, state=%lx\n",
+			FIELD_GET(RZG3S_PCI_PCSTAT1_LTSSM_STATE, tmp));
+		return ret;
+	}
+
+	lcs = readw(host->pcie + pcie_cap + PCI_EXP_LNKSTA);
+	cs2 = readl(host->axi + RZG3S_PCI_PCSTAT2);
+
+	link_speed = FIELD_GET(PCI_EXP_LNKSTA_CLS, lcs);
+	remote_supported_link_speeds = FIELD_GET(RZG3S_PCI_PCSTAT2_SDRIRE, cs2);
+
+	/*
+	 * Return if link is @ 5.0 GT/s or the connected device doesn't support
+	 * it.
+	 */
+	if (link_speed == PCI_EXP_LNKSTA_CLS_5_0GB ||
+	    !(remote_supported_link_speeds != GENMASK(PCI_EXP_LNKSTA_CLS_5_0GB - 1, 0)))
+		return 0;
+
+	/* Set target Link speed to 5.0 GT/s */
+	rzg3s_pcie_update_bits(host->pcie, pcie_cap + PCI_EXP_LNKCTL2,
+			       PCI_EXP_LNKCTL2_TLS,
+			       FIELD_PREP(PCI_EXP_LNKCTL2_TLS,
+					  PCI_EXP_LNKCTL2_TLS_5_0GT));
+
+	/* 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,
+					  PCI_EXP_LNKCTL2_TLS_5_0GT - 1));
+
+	ret = readl_poll_timeout(host->axi + RZG3S_PCI_PCSTAT2, cs2,
+				 (cs2 & RZG3S_PCI_PCSTAT2_LS_CHG_DONE),
+				 PCIE_LINK_WAIT_SLEEP_MS,
+				 PCIE_LINK_WAIT_SLEEP_MS *
+				 PCIE_LINK_WAIT_MAX_RETRIES * MILLI);
+
+	/*
+	 * 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(RZG3S_PCI_PERM_CFG_HWINIT_EN, host->axi + RZG3S_PCI_PERM);
+
+	/* Update vendor ID and device ID */
+	writew(host->vendor_id, host->pcie + PCI_VENDOR_ID);
+	writew(host->device_id, host->pcie + PCI_DEVICE_ID);
+
+	/* HW manual recommends to write 0xffffffff on initialization */
+	writel(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00L);
+	writel(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00U);
+
+	/* Update bus info. */
+	writeb(primary_bus, host->pcie + PCI_PRIMARY_BUS);
+	writeb(secondary_bus, host->pcie + PCI_SECONDARY_BUS);
+	writeb(subordinate_bus, host->pcie + PCI_SUBORDINATE_BUS);
+
+	/* Disable access control to the CFGU */
+	writel(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(RZG3S_PCI_PEIS0_DL_UPDOWN | RZG3S_PCI_PEIS0_RX_DLLP_PM_ENTER,
+	       host->axi + RZG3S_PCI_PEIS0);
+
+	/* Disable all interrupts */
+	writel(0, host->axi + RZG3S_PCI_PEIE0);
+
+	/* Clear all parity and ecc error interrupts */
+	writel(~0U, host->axi + RZG3S_PCI_PEIS1);
+
+	/* Disable all parity and ecc error interrupts */
+	writel(0, host->axi + RZG3S_PCI_PEIE1);
+
+	/* Clear all AXI master error interrupts */
+	writel(~0U, host->axi + RZG3S_PCI_AMEIS);
+
+	/* Clear all AXI slave error interrupts */
+	writel(~0U, host->axi + RZG3S_PCI_ASEIS1);
+
+	/* Clear all message receive interrupts */
+	writel(~0U, host->axi + RZG3S_PCI_MSGRCVIS);
+}
+
+static void rzg3s_pcie_power_resets_action(void *data)
+{
+	struct rzg3s_pcie_host *host = data;
+
+	reset_control_bulk_assert(host->data->num_power_resets,
+				  host->power_resets);
+}
+
+static void rzg3s_pcie_cfg_resets_action(void *data)
+{
+	struct rzg3s_pcie_host *host = data;
+
+	reset_control_bulk_assert(host->data->num_cfg_resets,
+				  host->cfg_resets);
+}
+
+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.
+	 */
+	usleep_range(5000, 5100);
+	return reset_control_bulk_deassert(data->num_power_resets,
+					   host->power_resets);
+}
+
+static int rzg3s_pcie_resets_prepare(struct rzg3s_pcie_host *host)
+{
+	const struct rzg3s_pcie_soc_data *data = host->data;
+	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 (unsigned int 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 (unsigned int 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;
+
+	ret = devm_reset_control_bulk_get_exclusive(host->dev,
+						    data->num_cfg_resets,
+						    host->cfg_resets);
+	if (ret)
+		return ret;
+
+	ret = rzg3s_pcie_power_resets_deassert(host);
+	if (ret)
+		return ret;
+
+	return devm_add_action_or_reset(host->dev,
+					rzg3s_pcie_power_resets_action, host);
+}
+
+static int rzg3s_pcie_host_init(struct rzg3s_pcie_host *host, bool probe)
+{
+	u32 val;
+	int ret;
+
+	/* Initialize the PCIe related registers */
+	ret = rzg3s_pcie_config_init(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)
+		return ret;
+
+	/* 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,
+				 PCIE_LINK_WAIT_SLEEP_MS *
+				 PCIE_LINK_WAIT_MAX_RETRIES * MILLI);
+	if (ret) {
+		reset_control_bulk_assert(host->data->num_cfg_resets,
+					  host->cfg_resets);
+		return ret;
+	}
+
+	val = readl(host->axi + RZG3S_PCI_PCSTAT2);
+	dev_info(host->dev, "PCIe link status [0x%x]\n", val);
+
+	val = FIELD_GET(RZG3S_PCI_PCSTAT2_STATE_RX_DETECT, val);
+	dev_info(host->dev, "PCIe x%d: link up\n", hweight32(val));
+
+	if (probe) {
+		ret = devm_add_action_or_reset(host->dev,
+					       rzg3s_pcie_cfg_resets_action,
+					       host);
+	}
+
+	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(upper_32_bits(cpu_addr), host->axi + RZG3S_PCI_ADESTU(id));
+	writel(lower_32_bits(cpu_addr), host->axi + RZG3S_PCI_ADESTL(id));
+
+	/* Set window size */
+	writel(upper_32_bits(size), host->axi + RZG3S_PCI_AWMASKU(id));
+	writel(lower_32_bits(size), host->axi + RZG3S_PCI_AWMASKL(id));
+
+	/* Set PCIe window base address and enable the window */
+	writel(upper_32_bits(pci_addr), host->axi + RZG3S_PCI_AWBASEU(id));
+	writel(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, -EINVAL,
+					     "Failed to set inbound windows!\n");
+
+		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);
+
+		/*
+		 * 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.
+		 */
+		size = roundup_pow_of_two(size) - 1;
+
+		cpu_addr = ALIGN(cpu_addr, SZ_4K);
+		pci_addr = ALIGN(pci_addr, SZ_4K);
+
+		rzg3s_pcie_set_inbound_window(host, cpu_addr, pci_addr, size,
+					      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(upper_32_bits(res_start), host->axi + RZG3S_PCI_PDESTU(id));
+	writel(lower_32_bits(res_start), host->axi + RZG3S_PCI_PDESTL(id));
+
+	/* Set PCIe window mask */
+	writel(upper_32_bits(size), host->axi + RZG3S_PCI_PWMASKU(id));
+	writel(lower_32_bits(size), host->axi + RZG3S_PCI_PWMASKL(id));
+
+	/* Set PCIe window base and enable the window */
+	writel(upper_32_bits(res_start), host->axi + RZG3S_PCI_PWBASEU(id));
+	writel(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, -EINVAL,
+					     "Failed to set outbound windows!\n");
+
+		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,
+	};
+
+	/*
+	 * Enable access permission for physical layer control and status
+	 * registers.
+	 */
+	writel(RZG3S_PCI_PERM_PIPE_PHY_REG_EN, host->axi + RZG3S_PCI_PERM);
+
+	for (u8 i = 0; i < RZG3S_PCI_PHY_XCFGD_NUM; i++)
+		writel(xcfgd_settings[i], host->axi + RZG3S_PCI_PHY_XCFGD(i));
+
+	for (u8 i = 0; i < RZG3S_PCI_PHY_XCFGA_CMN_NUM; i++) {
+		writel(xcfga_cmn_settings[i],
+		       host->axi + RZG3S_PCI_PHY_XCFGA_CMN(i));
+	}
+
+	for (u8 i = 0; i < RZG3S_PCI_PHY_XCFGA_RX_NUM; i++) {
+		writel(xcfga_rx_settings[i],
+		       host->axi + RZG3S_PCI_PHY_XCFGA_RX(i));
+	}
+
+	writel(0x107, host->axi + RZG3S_PCI_PHY_XCFGA_TX);
+
+	/* Select PHY settings values */
+	writel(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(0, host->axi + RZG3S_PCI_PERM);
+
+	return 0;
+}
+
+static void rzg3s_pcie_pm_runtime_put(void *data)
+{
+	pm_runtime_put_sync(data);
+}
+
+static void rzg3s_pcie_sysc_signal_action(void *data)
+{
+	struct regmap *sysc = data;
+
+	/*
+	 * SYSC RST_RSM_B signal need to be asserted before turning off the
+	 * power to the PHY.
+	 */
+	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));
+}
+
+static int
+rzg3s_pcie_host_setup(struct rzg3s_pcie_host *host,
+		      int (*intx_setup)(struct rzg3s_pcie_host *host),
+		      int (*msi_setup)(struct rzg3s_pcie_host *host),
+		      bool probe)
+{
+	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");
+
+	/* Set the PHY, if any */
+	if (host->data->init_phy) {
+		ret = host->data->init_phy(host);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					     "Failed to set the PHY!\n");
+	}
+
+	if (intx_setup) {
+		ret = intx_setup(host);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					     "Failed to setup INTx\n");
+	}
+
+	/* Set the MSIs */
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		ret = msi_setup(host);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					     "Failed to setup MSIs\n");
+	}
+
+	/* Initialize the host */
+	ret = rzg3s_pcie_host_init(host, probe);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to initialize the HW!\n");
+
+	/* Try to set maximum supported link speed */
+	ret = rzg3s_pcie_set_max_link_speed(host);
+	if (ret)
+		dev_info(dev, "Failed to set max link speed\n");
+
+	return 0;
+}
+
+static void rzg3s_pcie_host_remove_action(void *data)
+{
+	struct rzg3s_pcie_host *host = data;
+	struct pci_host_bridge *bridge = pci_host_bridge_from_priv(host);
+
+	pci_lock_rescan_remove();
+	pci_stop_root_bus(bridge->bus);
+	pci_remove_root_bus(bridge->bus);
+	pci_unlock_rescan_remove();
+}
+
+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;
+
+	ret = of_property_read_u32(np, "vendor-id", &host->vendor_id);
+	if (ret)
+		return ret;
+
+	ret = of_property_read_u32(np, "device-id", &host->device_id);
+	if (ret)
+		return ret;
+
+	host->sysc = syscon_node_to_regmap(sysc_np);
+	if (IS_ERR(host->sysc))
+		return PTR_ERR(host->sysc);
+
+	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)
+		return ret;
+
+	ret = devm_add_action_or_reset(dev, rzg3s_pcie_sysc_signal_action,
+				       host->sysc);
+	if (ret)
+		return ret;
+
+	ret = rzg3s_pcie_resets_prepare(host);
+	if (ret)
+		return ret;
+
+	ret = devm_pm_runtime_enable(dev);
+	if (ret)
+		return ret;
+
+	ret = pm_runtime_resume_and_get(dev);
+	if (ret)
+		return ret;
+
+	ret = devm_add_action_or_reset(dev, rzg3s_pcie_pm_runtime_put, dev);
+	if (ret)
+		return ret;
+
+	raw_spin_lock_init(&host->hw_lock);
+
+	ret = rzg3s_pcie_host_setup(host, rzg3s_pcie_intx_setup,
+				    rzg3s_pcie_msi_enable, true);
+	if (ret)
+		return ret;
+
+	msleep(PCIE_RESET_CONFIG_WAIT_MS);
+
+	bridge->sysdata = host;
+	bridge->ops = &rzg3s_pcie_root_ops;
+	bridge->child_ops = &rzg3s_pcie_child_ops;
+	ret = pci_host_probe(bridge);
+	if (ret)
+		return ret;
+
+	return devm_add_action_or_reset(dev, rzg3s_pcie_host_remove_action,
+					host);
+}
+
+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 regmap *sysc = host->sysc;
+	int ret;
+
+	ret = pm_runtime_put_sync(dev);
+	if (ret)
+		return ret;
+
+	ret = reset_control_bulk_assert(data->num_power_resets,
+					host->power_resets);
+	if (ret)
+		goto rpm_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);
+rpm_restore:
+	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, NULL, rzg3s_pcie_msi_hw_setup, false);
+	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 = {
+	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,r9a08g045s33-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 = rzg3s_pcie_probe,
+};
+module_platform_driver(rzg3s_pcie_driver);
+
+MODULE_DESCRIPTION("Renesas RZ/G3S PCIe host driver");
+MODULE_AUTHOR("Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>");
+MODULE_LICENSE("GPL");
-- 
2.43.0



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

* [PATCH v3 6/9] arm64: dts: renesas: r9a08g045s33: Add PCIe node
  2025-07-04 16:14 [PATCH v3 0/9] PCI: rzg3s-host: Add PCIe driver for Renesas RZ/G3S SoC Claudiu
                   ` (4 preceding siblings ...)
  2025-07-04 16:14 ` [PATCH v3 5/9] PCI: rzg3s-host: Add Initial PCIe Host Driver for Renesas RZ/G3S SoC Claudiu
@ 2025-07-04 16:14 ` Claudiu
  2025-08-08 12:13   ` Geert Uytterhoeven
  2025-07-04 16:14 ` [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe Claudiu
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 47+ messages in thread
From: Claudiu @ 2025-07-04 16:14 UTC (permalink / raw)
  To: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou
  Cc: claudiu.beznea, linux-pci, linux-renesas-soc, devicetree,
	linux-kernel, linux-arm-kernel, linux-clk, Claudiu Beznea,
	Wolfram Sang

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

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

Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v3:
- collected tags
- changed the ranges flags

Changes in v2:
- updated the dma-ranges to reflect the SoC capability; added a
  comment about it.
- updated clock-names, interrupt names
- dropped legacy-interrupt-controller node
- added interrupt-controller property
- moved renesas,sysc at the end of the node to comply with
  DT coding style

 arch/arm64/boot/dts/renesas/r9a08g045s33.dtsi | 60 +++++++++++++++++++
 1 file changed, 60 insertions(+)

diff --git a/arch/arm64/boot/dts/renesas/r9a08g045s33.dtsi b/arch/arm64/boot/dts/renesas/r9a08g045s33.dtsi
index 3351f26c7a2a..cff36e873e59 100644
--- a/arch/arm64/boot/dts/renesas/r9a08g045s33.dtsi
+++ b/arch/arm64/boot/dts/renesas/r9a08g045s33.dtsi
@@ -12,3 +12,63 @@
 / {
 	compatible = "renesas,r9a08g045s33", "renesas,r9a08g045";
 };
+
+&soc {
+	pcie: pcie@11e40000 {
+		compatible = "renesas,r9a08g045s33-pcie";
+		reg = <0 0x11e40000 0 0x10000>;
+		ranges = <0x02000000 0 0x30000000 0 0x30000000 0 0x8000000>;
+		/* Map all possible DRAM ranges (4 GB). */
+		dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0x1 0x0>;
+		bus-range = <0x0 0xff>;
+		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";
+		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>, /* INT A */
+				<0 0 0 2 &pcie 0 0 0 1>, /* INT B */
+				<0 0 0 3 &pcie 0 0 0 2>, /* INT C */
+				<0 0 0 4 &pcie 0 0 0 3>; /* INT D */
+		device_type = "pci";
+		num-lanes = <1>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		power-domains = <&cpg>;
+		vendor-id = <0x1912>;
+		device-id = <0x0033>;
+		renesas,sysc = <&sysc>;
+		status = "disabled";
+	};
+};
-- 
2.43.0



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

* [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe
  2025-07-04 16:14 [PATCH v3 0/9] PCI: rzg3s-host: Add PCIe driver for Renesas RZ/G3S SoC Claudiu
                   ` (5 preceding siblings ...)
  2025-07-04 16:14 ` [PATCH v3 6/9] arm64: dts: renesas: r9a08g045s33: Add PCIe node Claudiu
@ 2025-07-04 16:14 ` Claudiu
  2025-07-07  8:18   ` Biju Das
  2025-07-08 16:55   ` Bjorn Helgaas
  2025-07-04 16:14 ` [PATCH v3 8/9] arm64: dts: renesas: rzg3s-smarc: Enable PCIe Claudiu
                   ` (2 subsequent siblings)
  9 siblings, 2 replies; 47+ messages in thread
From: Claudiu @ 2025-07-04 16:14 UTC (permalink / raw)
  To: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou
  Cc: claudiu.beznea, linux-pci, linux-renesas-soc, devicetree,
	linux-kernel, linux-arm-kernel, linux-clk, Claudiu Beznea,
	Wolfram Sang

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

The first 128MB of memory is reserved on this board for secure area.
Update the PCIe dma-ranges property to reflect this.

Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v3:
- collected tags

Changes in v2:
- none, this patch is new

 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 39845faec894..1b03820a6f02 100644
--- a/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi
+++ b/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi
@@ -214,6 +214,11 @@ &sdhi2 {
 };
 #endif
 
+&pcie {
+	/* First 128MB is reserved for secure area. */
+	dma-ranges = <0x42000000 0 0x48000000 0 0x48000000 0x0 0x38000000>;
+};
+
 &pinctrl {
 #if SW_CONFIG3 == SW_ON
 	eth0-phy-irq-hog {
-- 
2.43.0



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

* [PATCH v3 8/9] arm64: dts: renesas: rzg3s-smarc: Enable PCIe
  2025-07-04 16:14 [PATCH v3 0/9] PCI: rzg3s-host: Add PCIe driver for Renesas RZ/G3S SoC Claudiu
                   ` (6 preceding siblings ...)
  2025-07-04 16:14 ` [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe Claudiu
@ 2025-07-04 16:14 ` Claudiu
  2025-07-04 16:14 ` [PATCH v3 9/9] arm64: defconfig: Enable PCIe for the Renesas RZ/G3S SoC Claudiu
  2025-07-07  6:41 ` [PATCH v3 0/9] PCI: rzg3s-host: Add PCIe driver for " Wolfram Sang
  9 siblings, 0 replies; 47+ messages in thread
From: Claudiu @ 2025-07-04 16:14 UTC (permalink / raw)
  To: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou
  Cc: claudiu.beznea, linux-pci, linux-renesas-soc, devicetree,
	linux-kernel, linux-arm-kernel, linux-clk, Claudiu Beznea,
	Wolfram Sang

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

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

Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v3:
- collected tags

Changes in v2:
- none

 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 5e044a4d0234..6e9e78aca0b0 100644
--- a/arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi
+++ b/arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi
@@ -132,6 +132,12 @@ power-monitor@44 {
 	};
 };
 
+&pcie {
+	pinctrl-0 = <&pcie_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
 &pinctrl {
 	audio_clock_pins: audio-clock {
 		pins = "AUDIO_CLK1", "AUDIO_CLK2";
@@ -159,6 +165,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] 47+ messages in thread

* [PATCH v3 9/9] arm64: defconfig: Enable PCIe for the Renesas RZ/G3S SoC
  2025-07-04 16:14 [PATCH v3 0/9] PCI: rzg3s-host: Add PCIe driver for Renesas RZ/G3S SoC Claudiu
                   ` (7 preceding siblings ...)
  2025-07-04 16:14 ` [PATCH v3 8/9] arm64: dts: renesas: rzg3s-smarc: Enable PCIe Claudiu
@ 2025-07-04 16:14 ` Claudiu
  2025-07-07  6:41 ` [PATCH v3 0/9] PCI: rzg3s-host: Add PCIe driver for " Wolfram Sang
  9 siblings, 0 replies; 47+ messages in thread
From: Claudiu @ 2025-07-04 16:14 UTC (permalink / raw)
  To: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou
  Cc: claudiu.beznea, linux-pci, linux-renesas-soc, devicetree,
	linux-kernel, linux-arm-kernel, linux-clk, Claudiu Beznea,
	Wolfram Sang

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

Enable PCIe for the Renesas RZ/G3S SoC.

Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v3:
- collected tags

Changes in v2:
- none

 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 739b19302865..b3533ba5be7e 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -227,6 +227,7 @@ CONFIG_PCIE_MEDIATEK_GEN3=m
 CONFIG_PCI_TEGRA=y
 CONFIG_PCIE_RCAR_HOST=y
 CONFIG_PCIE_RCAR_EP=y
+CONFIG_PCIE_RENESAS_RZG3S_HOST=m
 CONFIG_PCIE_ROCKCHIP_HOST=m
 CONFIG_PCI_XGENE=y
 CONFIG_PCI_IMX6_HOST=y
-- 
2.43.0



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

* Re: [PATCH v3 0/9] PCI: rzg3s-host: Add PCIe driver for Renesas RZ/G3S SoC
  2025-07-04 16:14 [PATCH v3 0/9] PCI: rzg3s-host: Add PCIe driver for Renesas RZ/G3S SoC Claudiu
                   ` (8 preceding siblings ...)
  2025-07-04 16:14 ` [PATCH v3 9/9] arm64: defconfig: Enable PCIe for the Renesas RZ/G3S SoC Claudiu
@ 2025-07-07  6:41 ` Wolfram Sang
  2025-07-07  8:05   ` Claudiu Beznea
  9 siblings, 1 reply; 47+ messages in thread
From: Wolfram Sang @ 2025-07-07  6:41 UTC (permalink / raw)
  To: Claudiu
  Cc: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou, linux-pci, linux-renesas-soc,
	devicetree, linux-kernel, linux-arm-kernel, linux-clk,
	Claudiu Beznea


> Please provide your feedback.

What is this based on? I tried v6.16-rc4 and renesas-driver/master. Or
is there a branch I could pull?



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

* Re: [PATCH v3 0/9] PCI: rzg3s-host: Add PCIe driver for Renesas RZ/G3S SoC
  2025-07-07  6:41 ` [PATCH v3 0/9] PCI: rzg3s-host: Add PCIe driver for " Wolfram Sang
@ 2025-07-07  8:05   ` Claudiu Beznea
  2025-07-07 12:01     ` Wolfram Sang
  0 siblings, 1 reply; 47+ messages in thread
From: Claudiu Beznea @ 2025-07-07  8:05 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou, linux-pci, linux-renesas-soc,
	devicetree, linux-kernel, linux-arm-kernel, linux-clk,
	Claudiu Beznea

Hi, Wolfram,

On 07.07.2025 09:41, Wolfram Sang wrote:
> 
>> Please provide your feedback.
> 
> What is this based on? I tried v6.16-rc4 and renesas-driver/master. Or
> is there a branch I could pull?
> 

This is based on next-20250703. I pushed it here, as well:
https://github.com/claudiubeznea/linux/commits/claudiu/rzg3s/pcie-v3/


Thank you for looking into this,
Claudiu


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

* RE: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe
  2025-07-04 16:14 ` [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe Claudiu
@ 2025-07-07  8:18   ` Biju Das
  2025-07-08 10:09     ` Claudiu Beznea
  2025-07-08 16:55   ` Bjorn Helgaas
  1 sibling, 1 reply; 47+ messages in thread
From: Biju Das @ 2025-07-07  8:18 UTC (permalink / raw)
  To: Claudiu.Beznea, bhelgaas@google.com, lpieralisi@kernel.org,
	kwilczynski@kernel.org, mani@kernel.org, robh@kernel.org,
	krzk+dt@kernel.org, conor+dt@kernel.org, geert+renesas@glider.be,
	magnus.damm@gmail.com, catalin.marinas@arm.com, will@kernel.org,
	mturquette@baylibre.com, sboyd@kernel.org, p.zabel@pengutronix.de,
	lizhi.hou@amd.com
  Cc: Claudiu.Beznea, linux-pci@vger.kernel.org,
	linux-renesas-soc@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, linux-clk@vger.kernel.org,
	Claudiu Beznea, Wolfram Sang

Hi Claudiu,

> -----Original Message-----
> From: Claudiu <claudiu.beznea@tuxon.dev>
> Sent: 04 July 2025 17:14
> Subject: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe
> 
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> 
> The first 128MB of memory is reserved on this board for secure area.
> Update the PCIe dma-ranges property to reflect this.

I see R-Car PCIe dma-ranges[1] and [2] maps all possible DDR area supported by the SoC?
Do we need to make board specific as well there?

[1] https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/arch/arm64/boot/dts/renesas/r8a774e1.dtsi?h=next-20250704#n2487
[2] https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/arch/arm64/boot/dts/renesas/salvator-common.dtsi?h=next-20250704

Cheers,
Biju

> 
> Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---
> 
> Changes in v3:
> - collected tags
> 
> Changes in v2:
> - none, this patch is new
> 
>  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 39845faec894..1b03820a6f02 100644
> --- a/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi
> +++ b/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi
> @@ -214,6 +214,11 @@ &sdhi2 {
>  };
>  #endif
> 
> +&pcie {
> +	/* First 128MB is reserved for secure area. */
> +	dma-ranges = <0x42000000 0 0x48000000 0 0x48000000 0x0 0x38000000>; };
> +
>  &pinctrl {
>  #if SW_CONFIG3 == SW_ON
>  	eth0-phy-irq-hog {
> --
> 2.43.0
> 



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

* Re: [PATCH v3 0/9] PCI: rzg3s-host: Add PCIe driver for Renesas RZ/G3S SoC
  2025-07-07  8:05   ` Claudiu Beznea
@ 2025-07-07 12:01     ` Wolfram Sang
  0 siblings, 0 replies; 47+ messages in thread
From: Wolfram Sang @ 2025-07-07 12:01 UTC (permalink / raw)
  To: Claudiu Beznea
  Cc: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou, linux-pci, linux-renesas-soc,
	devicetree, linux-kernel, linux-arm-kernel, linux-clk,
	Claudiu Beznea

On Mon, Jul 07, 2025 at 11:05:30AM +0300, Claudiu Beznea wrote:
> Hi, Wolfram,
> 
> On 07.07.2025 09:41, Wolfram Sang wrote:
> > 
> >> Please provide your feedback.
> > 
> > What is this based on? I tried v6.16-rc4 and renesas-driver/master. Or
> > is there a branch I could pull?
> > 
> 
> This is based on next-20250703. I pushed it here, as well:
> https://github.com/claudiubeznea/linux/commits/claudiu/rzg3s/pcie-v3/

Thank you, I doubled checked and tested again. Still works, great!



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

* Re: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe
  2025-07-07  8:18   ` Biju Das
@ 2025-07-08 10:09     ` Claudiu Beznea
  2025-07-09  5:05       ` Biju Das
  0 siblings, 1 reply; 47+ messages in thread
From: Claudiu Beznea @ 2025-07-08 10:09 UTC (permalink / raw)
  To: Biju Das, bhelgaas@google.com, lpieralisi@kernel.org,
	kwilczynski@kernel.org, mani@kernel.org, robh@kernel.org,
	krzk+dt@kernel.org, conor+dt@kernel.org, geert+renesas@glider.be,
	magnus.damm@gmail.com, catalin.marinas@arm.com, will@kernel.org,
	mturquette@baylibre.com, sboyd@kernel.org, p.zabel@pengutronix.de,
	lizhi.hou@amd.com
  Cc: linux-pci@vger.kernel.org, linux-renesas-soc@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, linux-clk@vger.kernel.org,
	Claudiu Beznea, Wolfram Sang

Hi, Biju,

On 07.07.2025 11:18, Biju Das wrote:
> Hi Claudiu,
> 
>> -----Original Message-----
>> From: Claudiu <claudiu.beznea@tuxon.dev>
>> Sent: 04 July 2025 17:14
>> Subject: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe
>>
>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>>
>> The first 128MB of memory is reserved on this board for secure area.
>> Update the PCIe dma-ranges property to reflect this.
> 
> I see R-Car PCIe dma-ranges[1] and [2] maps all possible DDR area supported by the SoC?
> Do we need to make board specific as well there?

I'm not familiar with R-Car, but if there are ranges reserved for other
purposes, I think we should reflect it in board specific device trees.

But that would have to be address though a different series as it has
nothing to do with enabling the RZ/G3S PCIe support.

Thank you,
Claudiu

> 
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/arch/arm64/boot/dts/renesas/r8a774e1.dtsi?h=next-20250704#n2487
> [2] https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/arch/arm64/boot/dts/renesas/salvator-common.dtsi?h=next-20250704
> 
> Cheers,
> Biju
> 
>>
>> Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
>> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>> ---
>>
>> Changes in v3:
>> - collected tags
>>
>> Changes in v2:
>> - none, this patch is new
>>
>>  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 39845faec894..1b03820a6f02 100644
>> --- a/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi
>> +++ b/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi
>> @@ -214,6 +214,11 @@ &sdhi2 {
>>  };
>>  #endif
>>
>> +&pcie {
>> +	/* First 128MB is reserved for secure area. */
>> +	dma-ranges = <0x42000000 0 0x48000000 0 0x48000000 0x0 0x38000000>; };
>> +
>>  &pinctrl {
>>  #if SW_CONFIG3 == SW_ON
>>  	eth0-phy-irq-hog {
>> --
>> 2.43.0
>>
> 



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

* Re: [PATCH v3 4/9] dt-bindings: PCI: renesas,r9a08g045s33-pcie: Add documentation for the PCIe IP on Renesas RZ/G3S
  2025-07-04 16:14 ` [PATCH v3 4/9] dt-bindings: PCI: renesas,r9a08g045s33-pcie: Add documentation for the PCIe IP on Renesas RZ/G3S Claudiu
@ 2025-07-08 16:34   ` Bjorn Helgaas
  2025-07-09  6:47     ` Krzysztof Kozlowski
  2025-08-08 11:25     ` Claudiu Beznea
  0 siblings, 2 replies; 47+ messages in thread
From: Bjorn Helgaas @ 2025-07-08 16:34 UTC (permalink / raw)
  To: Claudiu
  Cc: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou, linux-pci, linux-renesas-soc,
	devicetree, linux-kernel, linux-arm-kernel, linux-clk,
	Claudiu Beznea, Wolfram Sang

On Fri, Jul 04, 2025 at 07:14:04PM +0300, Claudiu wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> 
> 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 documentation for it.

> +++ b/Documentation/devicetree/bindings/pci/renesas,r9a08g045s33-pcie.yaml

The "r9a08g045s33" in the filename seems oddly specific.  Does it
leave room for descendants of the current chip that will inevitably be
added in the future?  Most bindings are named with a fairly generic
family name, e.g., "fsl,layerscape", "hisilicon,kirin", "intel,
keembay", "samsung,exynos", etc.

> +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,r9a08g045s33-pcie";
> +            reg = <0 0x11e40000 0 0x10000>;
> +            ranges = <0x02000000 0 0x30000000 0 0x30000000 0 0x8000000>;
> +            dma-ranges = <0x42000000 0 0x48000000 0 0x48000000 0 0x38000000>;
> +            bus-range = <0x0 0xff>;
> +            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";
> +            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>, /* INT A */
> +                            <0 0 0 2 &pcie 0 0 0 1>, /* INT B */
> +                            <0 0 0 3 &pcie 0 0 0 2>, /* INT C */
> +                            <0 0 0 4 &pcie 0 0 0 3>; /* INT D */

The spec styles these closed up: "INTA", "INTB", etc.

> +            device_type = "pci";
> +            num-lanes = <1>;
> +            #address-cells = <3>;
> +            #size-cells = <2>;
> +            power-domains = <&cpg>;
> +            vendor-id = <0x1912>;
> +            device-id = <0x0033>;

Some of this is specific to a Root Port, not to the Root Complex as a
whole.  E.g., device-type = "pci", num-lanes, vendor-id, device-id,
are Root Port properties.  Some of the resets, clocks, and interrupts
might be as well.

I really want to separate those out because even though this
particular version of this PCIe controller only supports a single Root
Port, there are other controllers (and possibly future iterations of
this controller) that support multiple Root Ports, and it makes
maintenance easier if the DT bindings and the driver structures are
similar.

This email includes pointers to sample DT bindings and driver code
that is structured to allow multiple Root Ports:

  https://lore.kernel.org/linux-pci/20250625221653.GA1590146@bhelgaas/

Bjorn


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

* Re: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe
  2025-07-04 16:14 ` [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe Claudiu
  2025-07-07  8:18   ` Biju Das
@ 2025-07-08 16:55   ` Bjorn Helgaas
  2025-08-08 11:24     ` Claudiu Beznea
  1 sibling, 1 reply; 47+ messages in thread
From: Bjorn Helgaas @ 2025-07-08 16:55 UTC (permalink / raw)
  To: Claudiu
  Cc: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou, linux-pci, linux-renesas-soc,
	devicetree, linux-kernel, linux-arm-kernel, linux-clk,
	Claudiu Beznea, Wolfram Sang

On Fri, Jul 04, 2025 at 07:14:07PM +0300, Claudiu wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> 
> The first 128MB of memory is reserved on this board for secure area.
> Update the PCIe dma-ranges property to reflect this.

Can we include a sentence or two about what the "secure area" means?
I don't know how to connect this with anything in the driver.

> Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---
> 
> Changes in v3:
> - collected tags
> 
> Changes in v2:
> - none, this patch is new
> 
>  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 39845faec894..1b03820a6f02 100644
> --- a/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi
> +++ b/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi
> @@ -214,6 +214,11 @@ &sdhi2 {
>  };
>  #endif
>  
> +&pcie {
> +	/* First 128MB is reserved for secure area. */
> +	dma-ranges = <0x42000000 0 0x48000000 0 0x48000000 0x0 0x38000000>;
> +};
> +
>  &pinctrl {
>  #if SW_CONFIG3 == SW_ON
>  	eth0-phy-irq-hog {
> -- 
> 2.43.0
> 


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

* Re: [PATCH v3 5/9] PCI: rzg3s-host: Add Initial PCIe Host Driver for Renesas RZ/G3S SoC
  2025-07-04 16:14 ` [PATCH v3 5/9] PCI: rzg3s-host: Add Initial PCIe Host Driver for Renesas RZ/G3S SoC Claudiu
@ 2025-07-08 19:24   ` Bjorn Helgaas
  2025-08-08 11:24     ` Claudiu Beznea
  2025-08-30  6:59   ` Manivannan Sadhasivam
  1 sibling, 1 reply; 47+ messages in thread
From: Bjorn Helgaas @ 2025-07-08 19:24 UTC (permalink / raw)
  To: Claudiu
  Cc: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou, linux-pci, linux-renesas-soc,
	devicetree, linux-kernel, linux-arm-kernel, linux-clk,
	Claudiu Beznea, Wolfram Sang, Nam Cao

[+cc Nam for MSI parent domain conversions, head of this thread at
https://lore.kernel.org/r/20250704161410.3931884-1-claudiu.beznea.uj@bp.renesas.com]

In subject:

  PCI: rzg3s-host: Add Renesas RZ/G3S SoC host driver

so the important stuff is up front instead of being wrapped at the
end.

On Fri, Jul 04, 2025 at 07:14:05PM +0300, Claudiu wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> 
> 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
> 
> Link: https://www.renesas.com/en/products/rz-g3s?queryID=695cc067c2d89e3f271d43656ede4d12
> Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

> +static bool 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);
> +
> +	return !!ret || (val & RZG3S_PCI_REQISS_MOR_STATUS);

From the context in the caller, I guess returning "true" means we
timed out or RZG3S_PCI_REQISS_MOR_STATUS contained some failure
status, and "false" means success.  This is a little bit mind-bending,
and it's a pain to have to deduce the bool meaning from the context.

Personally I would return 0 for success or a negative errno, e.g.,

  if (val & RZG3S_PCI_REQISS_MOR_STATUS)
    return -E<something>;
  return ret;

> +}
> +
> +static int rzg3s_pcie_child_read_conf(struct rzg3s_pcie_host *host,
> +				      struct pci_bus *bus,
> +				      unsigned int devfn, int where,
> +				      u32 *data)
> +{
> +	int ret;
> +
> +	bus->ops->map_bus(bus, devfn, where);
> +
> +	/* Set the type of request */
> +	writel(RZG3S_PCI_REQISS_TR_TP0_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(host->axi + RZG3S_PCI_REQRCVDAT);
> +
> +	return PCIBIOS_SUCCESSFUL;
> +}

> +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;
> +
> +	status = readl(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 (u8 reg_id = 0; reg_id < regs; reg_id++) {
> +		status = readl(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) {
> +		int ret;
> +
> +		ret = generic_handle_domain_irq(msi->domain->parent, bit);
> +		if (ret) {
> +			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(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(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 drop_mask = RZG3S_PCI_MSIRCVWADRL_ENA |
> +			RZG3S_PCI_MSIRCVWADRL_MSG_DATA_ENA;
> +	u32 lo, hi;
> +
> +	/*
> +	 * Enable and msg data enable bits are part of the address lo. Drop
> +	 * them.
> +	 */
> +	lo = readl(host->axi + RZG3S_PCI_MSIRCVWADRL) & ~drop_mask;
> +	hi = readl(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;
> +	int hwirq;
> +
> +	scoped_guard(mutex, &msi->map_lock) {
> +		hwirq = bitmap_find_free_region(msi->map, RZG3S_PCI_MSI_INT_NR,
> +						order_base_2(nr_irqs));
> +	}
> +
> +	if (hwirq < 0)
> +		return -ENOSPC;
> +
> +	for (unsigned int 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 MSI domain\n");
> +	}

Can you please rework this to follow what Nam Cao is doing for
existing drivers:
https://lore.kernel.org/r/cover.1750858083.git.namcao@linutronix.de

> +static int rzg3s_pcie_intx_setup(struct rzg3s_pcie_host *host)
> +{
> +	struct device *dev = host->dev;
> +
> +	for (int i = 0; i < PCI_NUM_INTX; i++) {
> +		struct platform_device *pdev = to_platform_device(dev);
> +		char irq_name[5] = {0};
> +		int irq;
> +
> +		scnprintf(irq_name, ARRAY_SIZE(irq_name), "int%c", 97 + i);

Can you use 'a' instead of 97?

> +		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",
> +					     65 + i);

And 'A' instead of 65?

> +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(RZG3S_PCI_PERM_CFG_HWINIT_EN, host->axi + RZG3S_PCI_PERM);
> +
> +	/* Update vendor ID and device ID */
> +	writew(host->vendor_id, host->pcie + PCI_VENDOR_ID);
> +	writew(host->device_id, host->pcie + PCI_DEVICE_ID);
> +
> +	/* HW manual recommends to write 0xffffffff on initialization */
> +	writel(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00L);
> +	writel(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00U);
> +
> +	/* Update bus info. */

Drop period at end to match other one-line single-sentence comments.

> +	writeb(primary_bus, host->pcie + PCI_PRIMARY_BUS);
> +	writeb(secondary_bus, host->pcie + PCI_SECONDARY_BUS);
> +	writeb(subordinate_bus, host->pcie + PCI_SUBORDINATE_BUS);
> +
> +	/* Disable access control to the CFGU */
> +	writel(0, host->axi + RZG3S_PCI_PERM);
> +
> +	return 0;
> +}

> +static int rzg3s_pcie_host_init(struct rzg3s_pcie_host *host, bool probe)
> +{
> +	u32 val;
> +	int ret;
> +
> +	/* Initialize the PCIe related registers */
> +	ret = rzg3s_pcie_config_init(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)
> +		return ret;
> +
> +	/* 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,
> +				 PCIE_LINK_WAIT_SLEEP_MS *
> +				 PCIE_LINK_WAIT_MAX_RETRIES * MILLI);
> +	if (ret) {
> +		reset_control_bulk_assert(host->data->num_cfg_resets,
> +					  host->cfg_resets);
> +		return ret;
> +	}
> +
> +	val = readl(host->axi + RZG3S_PCI_PCSTAT2);
> +	dev_info(host->dev, "PCIe link status [0x%x]\n", val);
> +
> +	val = FIELD_GET(RZG3S_PCI_PCSTAT2_STATE_RX_DETECT, val);
> +	dev_info(host->dev, "PCIe x%d: link up\n", hweight32(val));

Maybe a little verbose for production use?

> +	if (probe) {
> +		ret = devm_add_action_or_reset(host->dev,
> +					       rzg3s_pcie_cfg_resets_action,
> +					       host);
> +	}
> +
> +	return ret;
> +}

> +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,
> +	};
> +
> +	/*
> +	 * Enable access permission for physical layer control and status
> +	 * registers.
> +	 */
> +	writel(RZG3S_PCI_PERM_PIPE_PHY_REG_EN, host->axi + RZG3S_PCI_PERM);
> +
> +	for (u8 i = 0; i < RZG3S_PCI_PHY_XCFGD_NUM; i++)
> +		writel(xcfgd_settings[i], host->axi + RZG3S_PCI_PHY_XCFGD(i));
> +
> +	for (u8 i = 0; i < RZG3S_PCI_PHY_XCFGA_CMN_NUM; i++) {
> +		writel(xcfga_cmn_settings[i],
> +		       host->axi + RZG3S_PCI_PHY_XCFGA_CMN(i));
> +	}
> +
> +	for (u8 i = 0; i < RZG3S_PCI_PHY_XCFGA_RX_NUM; i++) {
> +		writel(xcfga_rx_settings[i],
> +		       host->axi + RZG3S_PCI_PHY_XCFGA_RX(i));
> +	}

Why "for (unsigned int i = 0; ...)" above and "u8" here?  Seems like
similar situation here and no benefit for using u8 vs unsigned int.

> +	writel(0x107, host->axi + RZG3S_PCI_PHY_XCFGA_TX);
> +
> +	/* Select PHY settings values */
> +	writel(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(0, host->axi + RZG3S_PCI_PERM);
> +
> +	return 0;
> +}

> +static int
> +rzg3s_pcie_host_setup(struct rzg3s_pcie_host *host,
> +		      int (*intx_setup)(struct rzg3s_pcie_host *host),
> +		      int (*msi_setup)(struct rzg3s_pcie_host *host),
> +		      bool probe)
> +{
> +	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");
> +
> +	/* Set the PHY, if any */
> +	if (host->data->init_phy) {
> +		ret = host->data->init_phy(host);
> +		if (ret)
> +			return dev_err_probe(dev, ret,
> +					     "Failed to set the PHY!\n");
> +	}
> +
> +	if (intx_setup) {
> +		ret = intx_setup(host);
> +		if (ret)
> +			return dev_err_probe(dev, ret,
> +					     "Failed to setup INTx\n");
> +	}
> +
> +	/* Set the MSIs */
> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> +		ret = msi_setup(host);
> +		if (ret)
> +			return dev_err_probe(dev, ret,
> +					     "Failed to setup MSIs\n");
> +	}
> +
> +	/* Initialize the host */

Superfluous comment since you have a good function name.

> +	ret = rzg3s_pcie_host_init(host, probe);
> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				     "Failed to initialize the HW!\n");
> +
> +	/* Try to set maximum supported link speed */

Ditto.

> +	ret = rzg3s_pcie_set_max_link_speed(host);
> +	if (ret)
> +		dev_info(dev, "Failed to set max link speed\n");
> +
> +	return 0;
> +}

> +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;
> +
> +	ret = of_property_read_u32(np, "vendor-id", &host->vendor_id);
> +	if (ret)
> +		return ret;
> +
> +	ret = of_property_read_u32(np, "device-id", &host->device_id);
> +	if (ret)
> +		return ret;
> +
> +	host->sysc = syscon_node_to_regmap(sysc_np);
> +	if (IS_ERR(host->sysc))
> +		return PTR_ERR(host->sysc);
> +
> +	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)
> +		return ret;
> +
> +	ret = devm_add_action_or_reset(dev, rzg3s_pcie_sysc_signal_action,
> +				       host->sysc);
> +	if (ret)
> +		return ret;
> +
> +	ret = rzg3s_pcie_resets_prepare(host);
> +	if (ret)
> +		return ret;
> +
> +	ret = devm_pm_runtime_enable(dev);
> +	if (ret)
> +		return ret;
> +
> +	ret = pm_runtime_resume_and_get(dev);
> +	if (ret)
> +		return ret;
> +
> +	ret = devm_add_action_or_reset(dev, rzg3s_pcie_pm_runtime_put, dev);
> +	if (ret)
> +		return ret;
> +
> +	raw_spin_lock_init(&host->hw_lock);
> +
> +	ret = rzg3s_pcie_host_setup(host, rzg3s_pcie_intx_setup,
> +				    rzg3s_pcie_msi_enable, true);
> +	if (ret)
> +		return ret;
> +
> +	msleep(PCIE_RESET_CONFIG_WAIT_MS);

We also call rzg3s_pcie_host_setup(), where rzg3s_pcie_host_init()
deasserts all the resets and waits for the link to come up, from
rzg3s_pcie_resume_noirq().

Seems like the rzg3s_pcie_resume_noirq() path needs similar delay?
Perhaps the delay should be in rzg3s_pcie_host_init() where the event
that defines the beginning of the required delay is?

> +	bridge->sysdata = host;
> +	bridge->ops = &rzg3s_pcie_root_ops;
> +	bridge->child_ops = &rzg3s_pcie_child_ops;
> +	ret = pci_host_probe(bridge);
> +	if (ret)
> +		return ret;
> +
> +	return devm_add_action_or_reset(dev, rzg3s_pcie_host_remove_action,
> +					host);
> +}

> +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, NULL, rzg3s_pcie_msi_hw_setup, false);
> +	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;
> +}


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

* RE: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe
  2025-07-08 10:09     ` Claudiu Beznea
@ 2025-07-09  5:05       ` Biju Das
  2025-08-08 11:28         ` Claudiu Beznea
  2025-08-08 11:45         ` Geert Uytterhoeven
  0 siblings, 2 replies; 47+ messages in thread
From: Biju Das @ 2025-07-09  5:05 UTC (permalink / raw)
  To: Claudiu.Beznea, bhelgaas@google.com, lpieralisi@kernel.org,
	kwilczynski@kernel.org, mani@kernel.org, robh@kernel.org,
	krzk+dt@kernel.org, conor+dt@kernel.org, geert+renesas@glider.be,
	magnus.damm@gmail.com, catalin.marinas@arm.com, will@kernel.org,
	mturquette@baylibre.com, sboyd@kernel.org, p.zabel@pengutronix.de,
	lizhi.hou@amd.com
  Cc: linux-pci@vger.kernel.org, linux-renesas-soc@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, linux-clk@vger.kernel.org,
	Claudiu Beznea, Wolfram Sang

Hi Claudiu Beznea,

> -----Original Message-----
> From: Claudiu Beznea <claudiu.beznea@tuxon.dev>
> Sent: 08 July 2025 11:10
> Subject: Re: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe
> 
> Hi, Biju,
> 
> On 07.07.2025 11:18, Biju Das wrote:
> > Hi Claudiu,
> >
> >> -----Original Message-----
> >> From: Claudiu <claudiu.beznea@tuxon.dev>
> >> Sent: 04 July 2025 17:14
> >> Subject: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update
> >> dma-ranges for PCIe
> >>
> >> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> >>
> >> The first 128MB of memory is reserved on this board for secure area.
> >> Update the PCIe dma-ranges property to reflect this.
> >
> > I see R-Car PCIe dma-ranges[1] and [2] maps all possible DDR area supported by the SoC?
> > Do we need to make board specific as well there?
> 
> I'm not familiar with R-Car, but if there are ranges reserved for other purposes, I think we should
> reflect it in board specific device trees.


Already Linux has this DDR info[1]. Linux provides DMA memory only from this region.

In your testing, have you faced any issue like system allocated DMA region other than [1]
and you don't want to use it, then the changes are ok??

Not sure, PCIe can work on internal memory such as SRAM?

[1]
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi?h=next-20250708#n31

Cheers,
Biju

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

* Re: [PATCH v3 4/9] dt-bindings: PCI: renesas,r9a08g045s33-pcie: Add documentation for the PCIe IP on Renesas RZ/G3S
  2025-07-08 16:34   ` Bjorn Helgaas
@ 2025-07-09  6:47     ` Krzysztof Kozlowski
  2025-07-09 13:24       ` Bjorn Helgaas
  2025-08-08 11:25     ` Claudiu Beznea
  1 sibling, 1 reply; 47+ messages in thread
From: Krzysztof Kozlowski @ 2025-07-09  6:47 UTC (permalink / raw)
  To: Bjorn Helgaas, Claudiu
  Cc: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou, linux-pci, linux-renesas-soc,
	devicetree, linux-kernel, linux-arm-kernel, linux-clk,
	Claudiu Beznea, Wolfram Sang

On 08/07/2025 18:34, Bjorn Helgaas wrote:
> On Fri, Jul 04, 2025 at 07:14:04PM +0300, Claudiu wrote:
>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>>
>> 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 documentation for it.
> 
>> +++ b/Documentation/devicetree/bindings/pci/renesas,r9a08g045s33-pcie.yaml
> 
> The "r9a08g045s33" in the filename seems oddly specific.  Does it
> leave room for descendants of the current chip that will inevitably be
> added in the future?  Most bindings are named with a fairly generic
> family name, e.g., "fsl,layerscape", "hisilicon,kirin", "intel,
> keembay", "samsung,exynos", etc.
> 

Bindings should be named by compatible, not in a generic way, so name is
correct. It can always grow with new compatibles even if name matches
old one, it's not a problem.


Best regards,
Krzysztof


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

* Re: [PATCH v3 4/9] dt-bindings: PCI: renesas,r9a08g045s33-pcie: Add documentation for the PCIe IP on Renesas RZ/G3S
  2025-07-09  6:47     ` Krzysztof Kozlowski
@ 2025-07-09 13:24       ` Bjorn Helgaas
  2025-07-09 13:43         ` Krzysztof Kozlowski
  0 siblings, 1 reply; 47+ messages in thread
From: Bjorn Helgaas @ 2025-07-09 13:24 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Claudiu, bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt,
	conor+dt, geert+renesas, magnus.damm, catalin.marinas, will,
	mturquette, sboyd, p.zabel, lizhi.hou, linux-pci,
	linux-renesas-soc, devicetree, linux-kernel, linux-arm-kernel,
	linux-clk, Claudiu Beznea, Wolfram Sang

On Wed, Jul 09, 2025 at 08:47:05AM +0200, Krzysztof Kozlowski wrote:
> On 08/07/2025 18:34, Bjorn Helgaas wrote:
> > On Fri, Jul 04, 2025 at 07:14:04PM +0300, Claudiu wrote:
> >> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> >>
> >> 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 documentation for it.
> > 
> >> +++ b/Documentation/devicetree/bindings/pci/renesas,r9a08g045s33-pcie.yaml
> > 
> > The "r9a08g045s33" in the filename seems oddly specific.  Does it
> > leave room for descendants of the current chip that will inevitably be
> > added in the future?  Most bindings are named with a fairly generic
> > family name, e.g., "fsl,layerscape", "hisilicon,kirin", "intel,
> > keembay", "samsung,exynos", etc.
> > 
> 
> Bindings should be named by compatible, not in a generic way, so name is
> correct. It can always grow with new compatibles even if name matches
> old one, it's not a problem.

Ok, thanks!

I guess that means I'm casting shade on the "r9a08g045s33" compatible.
I suppose it means something to somebody.

Bjorn


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

* Re: [PATCH v3 4/9] dt-bindings: PCI: renesas,r9a08g045s33-pcie: Add documentation for the PCIe IP on Renesas RZ/G3S
  2025-07-09 13:24       ` Bjorn Helgaas
@ 2025-07-09 13:43         ` Krzysztof Kozlowski
  2025-08-08 11:26           ` Claudiu Beznea
  0 siblings, 1 reply; 47+ messages in thread
From: Krzysztof Kozlowski @ 2025-07-09 13:43 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Claudiu, bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt,
	conor+dt, geert+renesas, magnus.damm, catalin.marinas, will,
	mturquette, sboyd, p.zabel, lizhi.hou, linux-pci,
	linux-renesas-soc, devicetree, linux-kernel, linux-arm-kernel,
	linux-clk, Claudiu Beznea, Wolfram Sang

On 09/07/2025 15:24, Bjorn Helgaas wrote:
> On Wed, Jul 09, 2025 at 08:47:05AM +0200, Krzysztof Kozlowski wrote:
>> On 08/07/2025 18:34, Bjorn Helgaas wrote:
>>> On Fri, Jul 04, 2025 at 07:14:04PM +0300, Claudiu wrote:
>>>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>>>>
>>>> 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 documentation for it.
>>>
>>>> +++ b/Documentation/devicetree/bindings/pci/renesas,r9a08g045s33-pcie.yaml
>>>
>>> The "r9a08g045s33" in the filename seems oddly specific.  Does it
>>> leave room for descendants of the current chip that will inevitably be
>>> added in the future?  Most bindings are named with a fairly generic
>>> family name, e.g., "fsl,layerscape", "hisilicon,kirin", "intel,
>>> keembay", "samsung,exynos", etc.
>>>
>>
>> Bindings should be named by compatible, not in a generic way, so name is
>> correct. It can always grow with new compatibles even if name matches
>> old one, it's not a problem.
> 
> Ok, thanks!
> 
> I guess that means I'm casting shade on the "r9a08g045s33" compatible.
> I suppose it means something to somebody.

Well, I hope it matches the name of the SoC, from which the compatible
should come :)

Best regards,
Krzysztof


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

* Re: [PATCH v3 2/9] clk: renesas: r9a08g045: Add clocks and resets support for PCIe
  2025-07-04 16:14 ` [PATCH v3 2/9] clk: renesas: r9a08g045: Add clocks and resets support for PCIe Claudiu
@ 2025-08-04 10:25   ` Geert Uytterhoeven
  0 siblings, 0 replies; 47+ messages in thread
From: Geert Uytterhoeven @ 2025-08-04 10:25 UTC (permalink / raw)
  To: Claudiu
  Cc: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	magnus.damm, catalin.marinas, will, mturquette, sboyd, p.zabel,
	lizhi.hou, linux-pci, linux-renesas-soc, devicetree, linux-kernel,
	linux-arm-kernel, linux-clk, Claudiu Beznea, Wolfram Sang

On Fri, 4 Jul 2025 at 18:14, Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> 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>

Thanks for your patch!

> --- a/drivers/clk/renesas/r9a08g045-cpg.c
> +++ b/drivers/clk/renesas/r9a08g045-cpg.c
> @@ -289,6 +289,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_clk1pm",           R9A08G045_PCI_CLKL1PM, R9A08G045_CLK_ZT, 0x608, 1,

pci_clkl1pm

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
i.e. will queue in renesas-clk for v6.18, with the above fixed.

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds


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

* Re: [PATCH v3 5/9] PCI: rzg3s-host: Add Initial PCIe Host Driver for Renesas RZ/G3S SoC
  2025-07-08 19:24   ` Bjorn Helgaas
@ 2025-08-08 11:24     ` Claudiu Beznea
  0 siblings, 0 replies; 47+ messages in thread
From: Claudiu Beznea @ 2025-08-08 11:24 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou, linux-pci, linux-renesas-soc,
	devicetree, linux-kernel, linux-arm-kernel, linux-clk,
	Claudiu Beznea, Wolfram Sang, Nam Cao

Hi, Bjorn,

Apolgies for taking so long to reply to this.

On 08.07.2025 22:24, Bjorn Helgaas wrote:
> [+cc Nam for MSI parent domain conversions, head of this thread at
> https://lore.kernel.org/r/20250704161410.3931884-1-claudiu.beznea.uj@bp.renesas.com]
> 
> In subject:
> 
>   PCI: rzg3s-host: Add Renesas RZ/G3S SoC host driver
> 
> so the important stuff is up front instead of being wrapped at the
> end.

OK

> 
> On Fri, Jul 04, 2025 at 07:14:05PM +0300, Claudiu wrote:
>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>>
>> 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
>>
>> Link: https://www.renesas.com/en/products/rz-g3s?queryID=695cc067c2d89e3f271d43656ede4d12
>> Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
>> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> 
>> +static bool 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);
>> +
>> +	return !!ret || (val & RZG3S_PCI_REQISS_MOR_STATUS);
> 
> From the context in the caller, I guess returning "true" means we
> timed out or RZG3S_PCI_REQISS_MOR_STATUS contained some failure
> status, and "false" means success.  This is a little bit mind-bending,
> and it's a pain to have to deduce the bool meaning from the context.
> 
> Personally I would return 0 for success or a negative errno, e.g.,
> 
>   if (val & RZG3S_PCI_REQISS_MOR_STATUS)
>     return -E<something>;
>   return ret;
> 

I'll change it in the next version.

>> +}
>> +
>> +static int rzg3s_pcie_child_read_conf(struct rzg3s_pcie_host *host,
>> +				      struct pci_bus *bus,
>> +				      unsigned int devfn, int where,
>> +				      u32 *data)
>> +{
>> +	int ret;
>> +
>> +	bus->ops->map_bus(bus, devfn, where);
>> +
>> +	/* Set the type of request */
>> +	writel(RZG3S_PCI_REQISS_TR_TP0_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(host->axi + RZG3S_PCI_REQRCVDAT);
>> +
>> +	return PCIBIOS_SUCCESSFUL;
>> +}
> 
>> +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;
>> +
>> +	status = readl(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 (u8 reg_id = 0; reg_id < regs; reg_id++) {
>> +		status = readl(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) {
>> +		int ret;
>> +
>> +		ret = generic_handle_domain_irq(msi->domain->parent, bit);
>> +		if (ret) {
>> +			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(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(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 drop_mask = RZG3S_PCI_MSIRCVWADRL_ENA |
>> +			RZG3S_PCI_MSIRCVWADRL_MSG_DATA_ENA;
>> +	u32 lo, hi;
>> +
>> +	/*
>> +	 * Enable and msg data enable bits are part of the address lo. Drop
>> +	 * them.
>> +	 */
>> +	lo = readl(host->axi + RZG3S_PCI_MSIRCVWADRL) & ~drop_mask;
>> +	hi = readl(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;
>> +	int hwirq;
>> +
>> +	scoped_guard(mutex, &msi->map_lock) {
>> +		hwirq = bitmap_find_free_region(msi->map, RZG3S_PCI_MSI_INT_NR,
>> +						order_base_2(nr_irqs));
>> +	}
>> +
>> +	if (hwirq < 0)
>> +		return -ENOSPC;
>> +
>> +	for (unsigned int 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 MSI domain\n");
>> +	}
> 
> Can you please rework this to follow what Nam Cao is doing for
> existing drivers:
> https://lore.kernel.org/r/cover.1750858083.git.namcao@linutronix.de

Sure! Thank you for pointing it!

> 
>> +static int rzg3s_pcie_intx_setup(struct rzg3s_pcie_host *host)
>> +{
>> +	struct device *dev = host->dev;
>> +
>> +	for (int i = 0; i < PCI_NUM_INTX; i++) {
>> +		struct platform_device *pdev = to_platform_device(dev);
>> +		char irq_name[5] = {0};
>> +		int irq;
>> +
>> +		scnprintf(irq_name, ARRAY_SIZE(irq_name), "int%c", 97 + i);
> 
> Can you use 'a' instead of 97?

Yes!

> 
>> +		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",
>> +					     65 + i);
> 
> And 'A' instead of 65?

Yes!

> 
>> +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(RZG3S_PCI_PERM_CFG_HWINIT_EN, host->axi + RZG3S_PCI_PERM);
>> +
>> +	/* Update vendor ID and device ID */
>> +	writew(host->vendor_id, host->pcie + PCI_VENDOR_ID);
>> +	writew(host->device_id, host->pcie + PCI_DEVICE_ID);
>> +
>> +	/* HW manual recommends to write 0xffffffff on initialization */
>> +	writel(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00L);
>> +	writel(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00U);
>> +
>> +	/* Update bus info. */
> 
> Drop period at end to match other one-line single-sentence comments.

Missed it. I'll drop it.

> 
>> +	writeb(primary_bus, host->pcie + PCI_PRIMARY_BUS);
>> +	writeb(secondary_bus, host->pcie + PCI_SECONDARY_BUS);
>> +	writeb(subordinate_bus, host->pcie + PCI_SUBORDINATE_BUS);
>> +
>> +	/* Disable access control to the CFGU */
>> +	writel(0, host->axi + RZG3S_PCI_PERM);
>> +
>> +	return 0;
>> +}
> 
>> +static int rzg3s_pcie_host_init(struct rzg3s_pcie_host *host, bool probe)
>> +{
>> +	u32 val;
>> +	int ret;
>> +
>> +	/* Initialize the PCIe related registers */
>> +	ret = rzg3s_pcie_config_init(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)
>> +		return ret;
>> +
>> +	/* 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,
>> +				 PCIE_LINK_WAIT_SLEEP_MS *
>> +				 PCIE_LINK_WAIT_MAX_RETRIES * MILLI);
>> +	if (ret) {
>> +		reset_control_bulk_assert(host->data->num_cfg_resets,
>> +					  host->cfg_resets);
>> +		return ret;
>> +	}
>> +
>> +	val = readl(host->axi + RZG3S_PCI_PCSTAT2);
>> +	dev_info(host->dev, "PCIe link status [0x%x]\n", val);
>> +
>> +	val = FIELD_GET(RZG3S_PCI_PCSTAT2_STATE_RX_DETECT, val);
>> +	dev_info(host->dev, "PCIe x%d: link up\n", hweight32(val));
> 
> Maybe a little verbose for production use?

OK, I'll drop it.

> 
>> +	if (probe) {
>> +		ret = devm_add_action_or_reset(host->dev,
>> +					       rzg3s_pcie_cfg_resets_action,
>> +					       host);
>> +	}
>> +
>> +	return ret;
>> +}
> 
>> +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,
>> +	};
>> +
>> +	/*
>> +	 * Enable access permission for physical layer control and status
>> +	 * registers.
>> +	 */
>> +	writel(RZG3S_PCI_PERM_PIPE_PHY_REG_EN, host->axi + RZG3S_PCI_PERM);
>> +
>> +	for (u8 i = 0; i < RZG3S_PCI_PHY_XCFGD_NUM; i++)
>> +		writel(xcfgd_settings[i], host->axi + RZG3S_PCI_PHY_XCFGD(i));
>> +
>> +	for (u8 i = 0; i < RZG3S_PCI_PHY_XCFGA_CMN_NUM; i++) {
>> +		writel(xcfga_cmn_settings[i],
>> +		       host->axi + RZG3S_PCI_PHY_XCFGA_CMN(i));
>> +	}
>> +
>> +	for (u8 i = 0; i < RZG3S_PCI_PHY_XCFGA_RX_NUM; i++) {
>> +		writel(xcfga_rx_settings[i],
>> +		       host->axi + RZG3S_PCI_PHY_XCFGA_RX(i));
>> +	}
> 
> Why "for (unsigned int i = 0; ...)" above and "u8" here?  Seems like
> similar situation here and no benefit for using u8 vs unsigned int.

OK, I'll use unsigned int here as well.

> 
>> +	writel(0x107, host->axi + RZG3S_PCI_PHY_XCFGA_TX);
>> +
>> +	/* Select PHY settings values */
>> +	writel(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(0, host->axi + RZG3S_PCI_PERM);
>> +
>> +	return 0;
>> +}
> 
>> +static int
>> +rzg3s_pcie_host_setup(struct rzg3s_pcie_host *host,
>> +		      int (*intx_setup)(struct rzg3s_pcie_host *host),
>> +		      int (*msi_setup)(struct rzg3s_pcie_host *host),
>> +		      bool probe)
>> +{
>> +	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");
>> +
>> +	/* Set the PHY, if any */
>> +	if (host->data->init_phy) {
>> +		ret = host->data->init_phy(host);
>> +		if (ret)
>> +			return dev_err_probe(dev, ret,
>> +					     "Failed to set the PHY!\n");
>> +	}
>> +
>> +	if (intx_setup) {
>> +		ret = intx_setup(host);
>> +		if (ret)
>> +			return dev_err_probe(dev, ret,
>> +					     "Failed to setup INTx\n");
>> +	}
>> +
>> +	/* Set the MSIs */
>> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>> +		ret = msi_setup(host);
>> +		if (ret)
>> +			return dev_err_probe(dev, ret,
>> +					     "Failed to setup MSIs\n");
>> +	}
>> +
>> +	/* Initialize the host */
> 
> Superfluous comment since you have a good function name.

Will drop it.

> 
>> +	ret = rzg3s_pcie_host_init(host, probe);
>> +	if (ret)
>> +		return dev_err_probe(dev, ret,
>> +				     "Failed to initialize the HW!\n");
>> +
>> +	/* Try to set maximum supported link speed */
> 
> Ditto.

OK.

> 
>> +	ret = rzg3s_pcie_set_max_link_speed(host);
>> +	if (ret)
>> +		dev_info(dev, "Failed to set max link speed\n");
>> +
>> +	return 0;
>> +}
> 
>> +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;
>> +
>> +	ret = of_property_read_u32(np, "vendor-id", &host->vendor_id);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = of_property_read_u32(np, "device-id", &host->device_id);
>> +	if (ret)
>> +		return ret;
>> +
>> +	host->sysc = syscon_node_to_regmap(sysc_np);
>> +	if (IS_ERR(host->sysc))
>> +		return PTR_ERR(host->sysc);
>> +
>> +	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)
>> +		return ret;
>> +
>> +	ret = devm_add_action_or_reset(dev, rzg3s_pcie_sysc_signal_action,
>> +				       host->sysc);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = rzg3s_pcie_resets_prepare(host);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = devm_pm_runtime_enable(dev);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = pm_runtime_resume_and_get(dev);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = devm_add_action_or_reset(dev, rzg3s_pcie_pm_runtime_put, dev);
>> +	if (ret)
>> +		return ret;
>> +
>> +	raw_spin_lock_init(&host->hw_lock);
>> +
>> +	ret = rzg3s_pcie_host_setup(host, rzg3s_pcie_intx_setup,
>> +				    rzg3s_pcie_msi_enable, true);
>> +	if (ret)
>> +		return ret;
>> +
>> +	msleep(PCIE_RESET_CONFIG_WAIT_MS);
> 
> We also call rzg3s_pcie_host_setup(), where rzg3s_pcie_host_init()
> deasserts all the resets and waits for the link to come up, from
> rzg3s_pcie_resume_noirq().
> 
> Seems like the rzg3s_pcie_resume_noirq() path needs similar delay?
> Perhaps the delay should be in rzg3s_pcie_host_init() where the event
> that defines the beginning of the required delay is?

You're right. I'll add the delay to rzg3s_pcie_host_setup().

> 
>> +	bridge->sysdata = host;
>> +	bridge->ops = &rzg3s_pcie_root_ops;
>> +	bridge->child_ops = &rzg3s_pcie_child_ops;
>> +	ret = pci_host_probe(bridge);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return devm_add_action_or_reset(dev, rzg3s_pcie_host_remove_action,
>> +					host);
>> +}
> 
>> +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, NULL, rzg3s_pcie_msi_hw_setup, false);
>> +	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;
>> +}



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

* Re: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe
  2025-07-08 16:55   ` Bjorn Helgaas
@ 2025-08-08 11:24     ` Claudiu Beznea
  0 siblings, 0 replies; 47+ messages in thread
From: Claudiu Beznea @ 2025-08-08 11:24 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou, linux-pci, linux-renesas-soc,
	devicetree, linux-kernel, linux-arm-kernel, linux-clk,
	Claudiu Beznea, Wolfram Sang

Hi, Bjorn,

On 08.07.2025 19:55, Bjorn Helgaas wrote:
> On Fri, Jul 04, 2025 at 07:14:07PM +0300, Claudiu wrote:
>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>>
>> The first 128MB of memory is reserved on this board for secure area.
>> Update the PCIe dma-ranges property to reflect this.
> 
> Can we include a sentence or two about what the "secure area" means?

I'll update it.

Basically, it is a RAM region that is used by firmware.

Thank you for your review,
Claudiu

> I don't know how to connect this with anything in the driver.
> 
>> Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
>> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>> ---
>>
>> Changes in v3:
>> - collected tags
>>
>> Changes in v2:
>> - none, this patch is new
>>
>>  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 39845faec894..1b03820a6f02 100644
>> --- a/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi
>> +++ b/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi
>> @@ -214,6 +214,11 @@ &sdhi2 {
>>  };
>>  #endif
>>  
>> +&pcie {
>> +	/* First 128MB is reserved for secure area. */
>> +	dma-ranges = <0x42000000 0 0x48000000 0 0x48000000 0x0 0x38000000>;
>> +};
>> +
>>  &pinctrl {
>>  #if SW_CONFIG3 == SW_ON
>>  	eth0-phy-irq-hog {
>> -- 
>> 2.43.0
>>



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

* Re: [PATCH v3 4/9] dt-bindings: PCI: renesas,r9a08g045s33-pcie: Add documentation for the PCIe IP on Renesas RZ/G3S
  2025-07-08 16:34   ` Bjorn Helgaas
  2025-07-09  6:47     ` Krzysztof Kozlowski
@ 2025-08-08 11:25     ` Claudiu Beznea
  2025-08-08 16:23       ` Bjorn Helgaas
  2025-08-28 19:11       ` claudiu beznea
  1 sibling, 2 replies; 47+ messages in thread
From: Claudiu Beznea @ 2025-08-08 11:25 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou, linux-pci, linux-renesas-soc,
	devicetree, linux-kernel, linux-arm-kernel, linux-clk,
	Claudiu Beznea, Wolfram Sang

Hi, Bjorn,

On 08.07.2025 19:34, Bjorn Helgaas wrote:
> On Fri, Jul 04, 2025 at 07:14:04PM +0300, Claudiu wrote:
>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>>
>> 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 documentation for it.
> 
>> +++ b/Documentation/devicetree/bindings/pci/renesas,r9a08g045s33-pcie.yaml
> 
> The "r9a08g045s33" in the filename seems oddly specific.  Does it
> leave room for descendants of the current chip that will inevitably be
> added in the future?  Most bindings are named with a fairly generic
> family name, e.g., "fsl,layerscape", "hisilicon,kirin", "intel,
> keembay", "samsung,exynos", etc.
> 
>> +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,r9a08g045s33-pcie";
>> +            reg = <0 0x11e40000 0 0x10000>;
>> +            ranges = <0x02000000 0 0x30000000 0 0x30000000 0 0x8000000>;
>> +            dma-ranges = <0x42000000 0 0x48000000 0 0x48000000 0 0x38000000>;
>> +            bus-range = <0x0 0xff>;
>> +            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";
>> +            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>, /* INT A */
>> +                            <0 0 0 2 &pcie 0 0 0 1>, /* INT B */
>> +                            <0 0 0 3 &pcie 0 0 0 2>, /* INT C */
>> +                            <0 0 0 4 &pcie 0 0 0 3>; /* INT D */
> 
> The spec styles these closed up: "INTA", "INTB", etc.

I'll update it.

> 
>> +            device_type = "pci";
>> +            num-lanes = <1>;
>> +            #address-cells = <3>;
>> +            #size-cells = <2>;
>> +            power-domains = <&cpg>;
>> +            vendor-id = <0x1912>;
>> +            device-id = <0x0033>;
> 
> Some of this is specific to a Root Port, not to the Root Complex as a
> whole.  E.g., device-type = "pci", num-lanes, vendor-id, device-id,
> are Root Port properties.  Some of the resets, clocks, and interrupts
> might be as well.
> 
> I really want to separate those out because even though this
> particular version of this PCIe controller only supports a single Root
> Port, there are other controllers (and possibly future iterations of
> this controller) that support multiple Root Ports, and it makes
> maintenance easier if the DT bindings and the driver structures are
> similar.

I'll ask the Renesas HW team about the resets and clocks as the HW manual
don't offer any information about this.

If they will confirm some of the clocks and/or resets could be controlled
as part of a port then patch 3/9 "PCI: of_property: Restore the arguments
of the next level parent" in this series will not be needed anymore. Would
you prefer me to abandon it or post it as individual patch, if any?

> 
> This email includes pointers to sample DT bindings and driver code
> that is structured to allow multiple Root Ports:
> 
>   https://lore.kernel.org/linux-pci/20250625221653.GA1590146@bhelgaas/

Thank you for this!

And, thank you for your review,
Claudiu

> 
> Bjorn



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

* Re: [PATCH v3 4/9] dt-bindings: PCI: renesas,r9a08g045s33-pcie: Add documentation for the PCIe IP on Renesas RZ/G3S
  2025-07-09 13:43         ` Krzysztof Kozlowski
@ 2025-08-08 11:26           ` Claudiu Beznea
  2025-08-08 12:03             ` Geert Uytterhoeven
  0 siblings, 1 reply; 47+ messages in thread
From: Claudiu Beznea @ 2025-08-08 11:26 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Bjorn Helgaas
  Cc: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou, linux-pci, linux-renesas-soc,
	devicetree, linux-kernel, linux-arm-kernel, linux-clk,
	Claudiu Beznea, Wolfram Sang

Hi, all,

Apologies for the late reply.


On 09.07.2025 16:43, Krzysztof Kozlowski wrote:
> On 09/07/2025 15:24, Bjorn Helgaas wrote:
>> On Wed, Jul 09, 2025 at 08:47:05AM +0200, Krzysztof Kozlowski wrote:
>>> On 08/07/2025 18:34, Bjorn Helgaas wrote:
>>>> On Fri, Jul 04, 2025 at 07:14:04PM +0300, Claudiu wrote:
>>>>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>>>>>
>>>>> 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 documentation for it.
>>>>
>>>>> +++ b/Documentation/devicetree/bindings/pci/renesas,r9a08g045s33-pcie.yaml
>>>>
>>>> The "r9a08g045s33" in the filename seems oddly specific.  Does it
>>>> leave room for descendants of the current chip that will inevitably be
>>>> added in the future?  Most bindings are named with a fairly generic
>>>> family name, e.g., "fsl,layerscape", "hisilicon,kirin", "intel,
>>>> keembay", "samsung,exynos", etc.
>>>>
>>>
>>> Bindings should be named by compatible, not in a generic way, so name is
>>> correct. It can always grow with new compatibles even if name matches
>>> old one, it's not a problem.
>>
>> Ok, thanks!
>>
>> I guess that means I'm casting shade on the "r9a08g045s33" compatible.
>> I suppose it means something to somebody.
> 
> Well, I hope it matches the name of the SoC, from which the compatible
> should come :)

The r9a08g45s33 is the part number of a device from the RZ/G3S group. This
particular device from RZ/G3S group supports PCIe.

In the RZ/G3S group there are more SoC variants (each with its own part
number). Not all support PCIe. To differentiate b/w PCIe and non-PCIe
variants it has been chosen to use the full part number here.

The available RZ/G3S part numbers are listed in Table 1.1 Product Lineup at [1]

(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)

We use a similar compatible scheme in other drivers.

Geert, I may be wrong. Please correct me otherwise, as I don't have the
full picture of this.

Maybe, the other variant would be to use "renesas,rzg3s-pcie", or maybe a
more generic one "renesas,rz-pcie" (though I think this last one is too
generic).

Geert, please let us know if you have some suggestions here with regards to
the compatible. The IP on RZ/G3S is compatible also with the one in RZ/V2H,
RZ/G3E.

Thank you,
Claudiu

[1]
https://www.renesas.com/en/products/rz-g3s?queryID=695cc067c2d89e3f271d43656ede4d12

> 
> Best regards,
> Krzysztof



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

* Re: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe
  2025-07-09  5:05       ` Biju Das
@ 2025-08-08 11:28         ` Claudiu Beznea
  2025-08-08 11:44           ` Biju Das
  2025-08-08 11:45         ` Geert Uytterhoeven
  1 sibling, 1 reply; 47+ messages in thread
From: Claudiu Beznea @ 2025-08-08 11:28 UTC (permalink / raw)
  To: Biju Das, bhelgaas@google.com, lpieralisi@kernel.org,
	kwilczynski@kernel.org, mani@kernel.org, robh@kernel.org,
	krzk+dt@kernel.org, conor+dt@kernel.org, geert+renesas@glider.be,
	magnus.damm@gmail.com, catalin.marinas@arm.com, will@kernel.org,
	mturquette@baylibre.com, sboyd@kernel.org, p.zabel@pengutronix.de,
	lizhi.hou@amd.com
  Cc: linux-pci@vger.kernel.org, linux-renesas-soc@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, linux-clk@vger.kernel.org,
	Claudiu Beznea, Wolfram Sang

Hi, Biju,

On 09.07.2025 08:05, Biju Das wrote:
> Hi Claudiu Beznea,
> 
>> -----Original Message-----
>> From: Claudiu Beznea <claudiu.beznea@tuxon.dev>
>> Sent: 08 July 2025 11:10
>> Subject: Re: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe
>>
>> Hi, Biju,
>>
>> On 07.07.2025 11:18, Biju Das wrote:
>>> Hi Claudiu,
>>>
>>>> -----Original Message-----
>>>> From: Claudiu <claudiu.beznea@tuxon.dev>
>>>> Sent: 04 July 2025 17:14
>>>> Subject: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update
>>>> dma-ranges for PCIe
>>>>
>>>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>>>>
>>>> The first 128MB of memory is reserved on this board for secure area.
>>>> Update the PCIe dma-ranges property to reflect this.
>>>
>>> I see R-Car PCIe dma-ranges[1] and [2] maps all possible DDR area supported by the SoC?
>>> Do we need to make board specific as well there?
>>
>> I'm not familiar with R-Car, but if there are ranges reserved for other purposes, I think we should
>> reflect it in board specific device trees.
> 
> 
> Already Linux has this DDR info[1]. Linux provides DMA memory only from this region.

What we provide though dma-ranges DT property is setup in the PCI
controller register corresponding to the AXI windows. It is the same in
case of R-Car (as of my investigation on driver).

> 
> In your testing, have you faced any issue like system allocated DMA region other than [1]
> and you don't want to use it, then the changes are ok??

I haven't currently encounter any issues.

As the values passed though the dma-ranges DT property are setup in the
controller register for AXI windows, and the DMA endpoints can act as bus
masters, to avoid any issue where the DMA endpoints may corrupt memory
specific to the secure area, I chose to update the "dma-ranges" though
board specific bindings (to reflect the presence of the secure area and
tell the PCIe controller to not use it).

> 
> Not sure, PCIe can work on internal memory such as SRAM?

Inbound window is RAM, outbound window is a PCIe specific memory described
though "ranges" DT property.

Thank you for your review,
Claudiu

> 
> [1]
> https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi?h=next-20250708#n31
> 
> Cheers,
> Biju



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

* RE: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe
  2025-08-08 11:28         ` Claudiu Beznea
@ 2025-08-08 11:44           ` Biju Das
  2025-08-08 12:03             ` Claudiu Beznea
  0 siblings, 1 reply; 47+ messages in thread
From: Biju Das @ 2025-08-08 11:44 UTC (permalink / raw)
  To: Claudiu.Beznea, bhelgaas@google.com, lpieralisi@kernel.org,
	kwilczynski@kernel.org, mani@kernel.org, robh@kernel.org,
	krzk+dt@kernel.org, conor+dt@kernel.org, geert+renesas@glider.be,
	magnus.damm, catalin.marinas@arm.com, will@kernel.org,
	mturquette@baylibre.com, sboyd@kernel.org, p.zabel@pengutronix.de,
	lizhi.hou@amd.com
  Cc: linux-pci@vger.kernel.org, linux-renesas-soc@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, linux-clk@vger.kernel.org,
	Claudiu Beznea, wsa+renesas



> -----Original Message-----
> From: Claudiu Beznea <claudiu.beznea@tuxon.dev>
> Sent: 08 August 2025 12:28
.org; Claudiu Beznea
> <claudiu.beznea.uj@bp.renesas.com>; wsa+renesas <wsa+renesas@sang-engineering.com>
> Subject: Re: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe
> 
> Hi, Biju,
> 
> On 09.07.2025 08:05, Biju Das wrote:
> > Hi Claudiu Beznea,
> >
> >> -----Original Message-----
> >> From: Claudiu Beznea <claudiu.beznea@tuxon.dev>
> >> Sent: 08 July 2025 11:10
> >> Subject: Re: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som:
> >> Update dma-ranges for PCIe
> >>
> >> Hi, Biju,
> >>
> >> On 07.07.2025 11:18, Biju Das wrote:
> >>> Hi Claudiu,
> >>>
> >>>> -----Original Message-----
> >>>> From: Claudiu <claudiu.beznea@tuxon.dev>
> >>>> Sent: 04 July 2025 17:14
> >>>> Subject: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som:
> >>>> Update dma-ranges for PCIe
> >>>>
> >>>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> >>>>
> >>>> The first 128MB of memory is reserved on this board for secure area.
> >>>> Update the PCIe dma-ranges property to reflect this.
> >>>
> >>> I see R-Car PCIe dma-ranges[1] and [2] maps all possible DDR area supported by the SoC?
> >>> Do we need to make board specific as well there?
> >>
> >> I'm not familiar with R-Car, but if there are ranges reserved for
> >> other purposes, I think we should reflect it in board specific device trees.
> >
> >
> > Already Linux has this DDR info[1]. Linux provides DMA memory only from this region.
> 
> What we provide though dma-ranges DT property is setup in the PCI controller register corresponding to
> the AXI windows. It is the same in case of R-Car (as of my investigation on driver).
> 
> >
> > In your testing, have you faced any issue like system allocated DMA
> > region other than [1] and you don't want to use it, then the changes are ok??
> 
> I haven't currently encounter any issues.
> 
> As the values passed though the dma-ranges DT property are setup in the controller register for AXI
> windows, and the DMA endpoints can act as bus masters, to avoid any issue where the DMA endpoints may
> corrupt memory specific to the secure area, I chose to update the "dma-ranges" though board specific
> bindings (to reflect the presence of the secure area and tell the PCIe controller to not use it).
> 
> >
> > Not sure, PCIe can work on internal memory such as SRAM?
> 
> Inbound window is RAM, outbound window is a PCIe specific memory described though "ranges" DT property.

You mean SRAM cannot work on PCIe subsystem and work only for DRAM
that is the reason you are not defining SRAM region in "dma-ranges". Am I correct?

Cheers,
Biju

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

* Re: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe
  2025-07-09  5:05       ` Biju Das
  2025-08-08 11:28         ` Claudiu Beznea
@ 2025-08-08 11:45         ` Geert Uytterhoeven
  1 sibling, 0 replies; 47+ messages in thread
From: Geert Uytterhoeven @ 2025-08-08 11:45 UTC (permalink / raw)
  To: Biju Das
  Cc: Claudiu.Beznea, bhelgaas@google.com, lpieralisi@kernel.org,
	kwilczynski@kernel.org, mani@kernel.org, robh@kernel.org,
	krzk+dt@kernel.org, conor+dt@kernel.org, geert+renesas@glider.be,
	magnus.damm@gmail.com, catalin.marinas@arm.com, will@kernel.org,
	mturquette@baylibre.com, sboyd@kernel.org, p.zabel@pengutronix.de,
	lizhi.hou@amd.com, linux-pci@vger.kernel.org,
	linux-renesas-soc@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, linux-clk@vger.kernel.org,
	Claudiu Beznea, Wolfram Sang

On Wed, 9 Jul 2025 at 07:05, Biju Das <biju.das.jz@bp.renesas.com> wrote:
> > From: Claudiu Beznea <claudiu.beznea@tuxon.dev>
> > On 07.07.2025 11:18, Biju Das wrote:
> > >> From: Claudiu <claudiu.beznea@tuxon.dev>
> > >> Sent: 04 July 2025 17:14
> > >> Subject: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update
> > >> dma-ranges for PCIe
> > >>
> > >> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> > >>
> > >> The first 128MB of memory is reserved on this board for secure area.
> > >> Update the PCIe dma-ranges property to reflect this.
> > >
> > > I see R-Car PCIe dma-ranges[1] and [2] maps all possible DDR area supported by the SoC?
> > > Do we need to make board specific as well there?
> >
> > I'm not familiar with R-Car, but if there are ranges reserved for other purposes, I think we should
> > reflect it in board specific device trees.
>
> Already Linux has this DDR info[1]. Linux provides DMA memory only from this region.
>
> In your testing, have you faced any issue like system allocated DMA region other than [1]
> and you don't want to use it, then the changes are ok??

Exactly.  PCI memory must be located in the intersection of
dma-ranges in r9a08g045s33.dtsi and the various memory nodes in
rzg3s-smarc-som.dtsi.  The latter already excludes the secure area.

> Not sure, PCIe can work on internal memory such as SRAM?

If that is the case, it should be reflected in r9a08g045s33.dtsi.

> [1]
> https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi?h=next-20250708#n31

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds


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

* Re: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe
  2025-08-08 11:44           ` Biju Das
@ 2025-08-08 12:03             ` Claudiu Beznea
  0 siblings, 0 replies; 47+ messages in thread
From: Claudiu Beznea @ 2025-08-08 12:03 UTC (permalink / raw)
  To: Biju Das, bhelgaas@google.com, lpieralisi@kernel.org,
	kwilczynski@kernel.org, mani@kernel.org, robh@kernel.org,
	krzk+dt@kernel.org, conor+dt@kernel.org, geert+renesas@glider.be,
	magnus.damm, catalin.marinas@arm.com, will@kernel.org,
	mturquette@baylibre.com, sboyd@kernel.org, p.zabel@pengutronix.de,
	lizhi.hou@amd.com
  Cc: linux-pci@vger.kernel.org, linux-renesas-soc@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, linux-clk@vger.kernel.org,
	Claudiu Beznea, wsa+renesas



On 08.08.2025 14:44, Biju Das wrote:
> 
> 
>> -----Original Message-----
>> From: Claudiu Beznea <claudiu.beznea@tuxon.dev>
>> Sent: 08 August 2025 12:28
> .org; Claudiu Beznea
>> <claudiu.beznea.uj@bp.renesas.com>; wsa+renesas <wsa+renesas@sang-engineering.com>
>> Subject: Re: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe
>>
>> Hi, Biju,
>>
>> On 09.07.2025 08:05, Biju Das wrote:
>>> Hi Claudiu Beznea,
>>>
>>>> -----Original Message-----
>>>> From: Claudiu Beznea <claudiu.beznea@tuxon.dev>
>>>> Sent: 08 July 2025 11:10
>>>> Subject: Re: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som:
>>>> Update dma-ranges for PCIe
>>>>
>>>> Hi, Biju,
>>>>
>>>> On 07.07.2025 11:18, Biju Das wrote:
>>>>> Hi Claudiu,
>>>>>
>>>>>> -----Original Message-----
>>>>>> From: Claudiu <claudiu.beznea@tuxon.dev>
>>>>>> Sent: 04 July 2025 17:14
>>>>>> Subject: [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som:
>>>>>> Update dma-ranges for PCIe
>>>>>>
>>>>>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>>>>>>
>>>>>> The first 128MB of memory is reserved on this board for secure area.
>>>>>> Update the PCIe dma-ranges property to reflect this.
>>>>>
>>>>> I see R-Car PCIe dma-ranges[1] and [2] maps all possible DDR area supported by the SoC?
>>>>> Do we need to make board specific as well there?
>>>>
>>>> I'm not familiar with R-Car, but if there are ranges reserved for
>>>> other purposes, I think we should reflect it in board specific device trees.
>>>
>>>
>>> Already Linux has this DDR info[1]. Linux provides DMA memory only from this region.
>>
>> What we provide though dma-ranges DT property is setup in the PCI controller register corresponding to
>> the AXI windows. It is the same in case of R-Car (as of my investigation on driver).
>>
>>>
>>> In your testing, have you faced any issue like system allocated DMA
>>> region other than [1] and you don't want to use it, then the changes are ok??
>>
>> I haven't currently encounter any issues.
>>
>> As the values passed though the dma-ranges DT property are setup in the controller register for AXI
>> windows, and the DMA endpoints can act as bus masters, to avoid any issue where the DMA endpoints may
>> corrupt memory specific to the secure area, I chose to update the "dma-ranges" though board specific
>> bindings (to reflect the presence of the secure area and tell the PCIe controller to not use it).
>>
>>>
>>> Not sure, PCIe can work on internal memory such as SRAM?
>>
>> Inbound window is RAM, outbound window is a PCIe specific memory described though "ranges" DT property.
> 
> You mean SRAM cannot work on PCIe subsystem and work only for DRAM

This PCIe driver uses the PCIe specific memory (named "PCIe area" in Figure
5.2 Overall Address Space or RZ/G3S HW manual) and DRAM.

> that is the reason you are not defining SRAM region in "dma-ranges". Am I correct?

The DRAM region is described though dma-ranges, the PCIe memory is
described through ranges property. The above is from this series:

dma-ranges = <0x42000000 0 0x48000000 0 0x48000000 0x0 0x38000000>;
ranges = <0x02000000 0 0x30000000 0 0x30000000 0 0x8000000>;

Thank you,
Claudiu

> 
> Cheers,
> Biju



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

* Re: [PATCH v3 4/9] dt-bindings: PCI: renesas,r9a08g045s33-pcie: Add documentation for the PCIe IP on Renesas RZ/G3S
  2025-08-08 11:26           ` Claudiu Beznea
@ 2025-08-08 12:03             ` Geert Uytterhoeven
  0 siblings, 0 replies; 47+ messages in thread
From: Geert Uytterhoeven @ 2025-08-08 12:03 UTC (permalink / raw)
  To: Claudiu Beznea
  Cc: Krzysztof Kozlowski, Bjorn Helgaas, bhelgaas, lpieralisi,
	kwilczynski, mani, robh, krzk+dt, conor+dt, geert+renesas,
	magnus.damm, catalin.marinas, will, mturquette, sboyd, p.zabel,
	lizhi.hou, linux-pci, linux-renesas-soc, devicetree, linux-kernel,
	linux-arm-kernel, linux-clk, Claudiu Beznea, Wolfram Sang

Hi Claudiu,

On Fri, 8 Aug 2025 at 13:44, Claudiu Beznea <claudiu.beznea@tuxon.dev> wrote:
> On 09.07.2025 16:43, Krzysztof Kozlowski wrote:
> > On 09/07/2025 15:24, Bjorn Helgaas wrote:
> >> On Wed, Jul 09, 2025 at 08:47:05AM +0200, Krzysztof Kozlowski wrote:
> >>> On 08/07/2025 18:34, Bjorn Helgaas wrote:
> >>>> On Fri, Jul 04, 2025 at 07:14:04PM +0300, Claudiu wrote:
> >>>>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> >>>>>
> >>>>> 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 documentation for it.
> >>>>
> >>>>> +++ b/Documentation/devicetree/bindings/pci/renesas,r9a08g045s33-pcie.yaml
> >>>>
> >>>> The "r9a08g045s33" in the filename seems oddly specific.  Does it
> >>>> leave room for descendants of the current chip that will inevitably be
> >>>> added in the future?  Most bindings are named with a fairly generic
> >>>> family name, e.g., "fsl,layerscape", "hisilicon,kirin", "intel,
> >>>> keembay", "samsung,exynos", etc.
> >>>>
> >>>
> >>> Bindings should be named by compatible, not in a generic way, so name is
> >>> correct. It can always grow with new compatibles even if name matches
> >>> old one, it's not a problem.
> >>
> >> Ok, thanks!
> >>
> >> I guess that means I'm casting shade on the "r9a08g045s33" compatible.
> >> I suppose it means something to somebody.
> >
> > Well, I hope it matches the name of the SoC, from which the compatible
> > should come :)
>
> The r9a08g45s33 is the part number of a device from the RZ/G3S group. This
> particular device from RZ/G3S group supports PCIe.
>
> In the RZ/G3S group there are more SoC variants (each with its own part
> number). Not all support PCIe. To differentiate b/w PCIe and non-PCIe
> variants it has been chosen to use the full part number here.
>
> The available RZ/G3S part numbers are listed in Table 1.1 Product Lineup at [1]
>
> (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)
>
> We use a similar compatible scheme in other drivers.
>
> Geert, I may be wrong. Please correct me otherwise, as I don't have the
> full picture of this.
>
> Maybe, the other variant would be to use "renesas,rzg3s-pcie", or maybe a
> more generic one "renesas,rz-pcie" (though I think this last one is too
> generic).

Both would be too generic for the myriad of RZ devices.

AFAIU, the R9A08G045Sxx variants are really the same SoC, with some
hardware modules disabled/nonfunctional.  This is typically handled by:
  1. Using the base part number (r9a08g045) in the compatible value,
  2. Having the device node in the base .dtsi,
  3. Deleting nodes in the variant-specific .dtsi file when needed
     (see e.g. arch/arm64/boot/dts/renesas/r9a09g047{,e[35]7}.dtsi)

Hence as R9A08G045S13, R9A08G045S17, R9A08G045S33, and
R9A08G045S37 all have PCIe, I think it is more appropriate
to use "renesas,r9a08g045-pcie" as the compatible value than
"renesas,r9a08g045s33-pcie".

> Geert, please let us know if you have some suggestions here with regards to
> the compatible. The IP on RZ/G3S is compatible also with the one in RZ/V2H,
> RZ/G3E.

RZ/V2H and RZ/G3E can use "renesas,r9a09g057-pcie" resp.
"renesas,r9a09g047-pcie", with "renesas,r9a08g045-pcie" as a fallback.

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds


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

* Re: [PATCH v3 6/9] arm64: dts: renesas: r9a08g045s33: Add PCIe node
  2025-07-04 16:14 ` [PATCH v3 6/9] arm64: dts: renesas: r9a08g045s33: Add PCIe node Claudiu
@ 2025-08-08 12:13   ` Geert Uytterhoeven
  0 siblings, 0 replies; 47+ messages in thread
From: Geert Uytterhoeven @ 2025-08-08 12:13 UTC (permalink / raw)
  To: Claudiu
  Cc: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	magnus.damm, catalin.marinas, will, mturquette, sboyd, p.zabel,
	lizhi.hou, linux-pci, linux-renesas-soc, devicetree, linux-kernel,
	linux-arm-kernel, linux-clk, Claudiu Beznea, Wolfram Sang

Hi Claudiu,

On Fri, 4 Jul 2025 at 18:14, Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> The RZ/G3S SoC has a variant (R9A08G045S33) which support PCIe. Add the

supports

> PCIe node.
>
> Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

Thanks for your patch!

> --- a/arch/arm64/boot/dts/renesas/r9a08g045s33.dtsi
> +++ b/arch/arm64/boot/dts/renesas/r9a08g045s33.dtsi
> @@ -12,3 +12,63 @@
>  / {
>         compatible = "renesas,r9a08g045s33", "renesas,r9a08g045";
>  };
> +
> +&soc {
> +       pcie: pcie@11e40000 {
> +               compatible = "renesas,r9a08g045s33-pcie";

In light of the discussion on "[PATCH v3 4/9] dt-bindings: PCI:
renesas,r9a08g045s33-pcie: Add documentation for the PCIe IP on Renesas
RZ/G3S", this should be "renesas,r9a08g045-pcie", and the device node
should be added to the base r9a08g045.dtsi instead (else everything
has to be duplicated in r9a08g045s{13,17,37}.dtsi).  When support for
the variants without PCIe is added, the pcie node should be deleted
using /delete-node/ in r9a08g045s{11,15,31,35}.dtsi.

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds


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

* Re: [PATCH v3 4/9] dt-bindings: PCI: renesas,r9a08g045s33-pcie: Add documentation for the PCIe IP on Renesas RZ/G3S
  2025-08-08 11:25     ` Claudiu Beznea
@ 2025-08-08 16:23       ` Bjorn Helgaas
  2025-08-28 19:11       ` claudiu beznea
  1 sibling, 0 replies; 47+ messages in thread
From: Bjorn Helgaas @ 2025-08-08 16:23 UTC (permalink / raw)
  To: Claudiu Beznea
  Cc: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou, linux-pci, linux-renesas-soc,
	devicetree, linux-kernel, linux-arm-kernel, linux-clk,
	Claudiu Beznea, Wolfram Sang

On Fri, Aug 08, 2025 at 02:25:42PM +0300, Claudiu Beznea wrote:
> On 08.07.2025 19:34, Bjorn Helgaas wrote:
> > On Fri, Jul 04, 2025 at 07:14:04PM +0300, Claudiu wrote:
> >> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> >>
> >> 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 documentation for it.
> > 
> >> +++ b/Documentation/devicetree/bindings/pci/renesas,r9a08g045s33-pcie.yaml

> >> +        pcie@11e40000 {
> >> +            compatible = "renesas,r9a08g045s33-pcie";
> >> +            reg = <0 0x11e40000 0 0x10000>;
> >> +            ranges = <0x02000000 0 0x30000000 0 0x30000000 0 0x8000000>;
> >> +            dma-ranges = <0x42000000 0 0x48000000 0 0x48000000 0 0x38000000>;
> >> +            bus-range = <0x0 0xff>;
> ...

> >> +            device_type = "pci";
> >> +            num-lanes = <1>;
> >> +            #address-cells = <3>;
> >> +            #size-cells = <2>;
> >> +            power-domains = <&cpg>;
> >> +            vendor-id = <0x1912>;
> >> +            device-id = <0x0033>;
> > 
> > Some of this is specific to a Root Port, not to the Root Complex
> > as a whole.  E.g., device-type = "pci", num-lanes, vendor-id,
> > device-id, are Root Port properties.  Some of the resets, clocks,
> > and interrupts might be as well.
> > 
> > I really want to separate those out because even though this
> > particular version of this PCIe controller only supports a single
> > Root Port, there are other controllers (and possibly future
> > iterations of this controller) that support multiple Root Ports,
> > and it makes maintenance easier if the DT bindings and the driver
> > structures are similar.
> 
> I'll ask the Renesas HW team about the resets and clocks as the HW
> manual don't offer any information about this.
> 
> If they will confirm some of the clocks and/or resets could be
> controlled as part of a port then patch 3/9 "PCI: of_property:
> Restore the arguments of the next level parent" in this series will
> not be needed anymore. Would you prefer me to abandon it or post it
> as individual patch, if any?

[PATCH v3 3/9] ("PCI: of_property: Restore the arguments of the next
level parent") isn't specific to Renesas RZ/G3S and it doesn't look
like it has anything to do with clocks or resets.  I don't understand
the patch well enough to know whether you should keep it, but it does
look like you should post it separate from the RZ/G3S driver.

When the devicetree contains required information specific to Root
Ports, I would prefer that to be in a separate "pcie@x,y" stanza, even
if there are clocks or resets that apply to all Root Ports.

"num-lanes" is obviously specific to an individual Root Port because
a Root Complex doesn't have lanes at all.  But in the case of RZ/G3S,
I'm not sure "num-lanes" is required in the devicetree; I don't see it
being used in the driver.  If it's not needed, I would just omit it.

It looks like the driver *does* need "vendor-id" and "device-id"
though, and those also are specific to a Root Port because a Root
Complex is not a PCI device and doesn't have its own Vendor or Device
ID.  So I would like them to be in a per-Root Port stanza.  If there
are resets or clocks that affect a Root Port but not the Root Complex
as a whole, they should also be in the Root Port stanza.

Bjorn


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

* Re: [PATCH v3 3/9] PCI: of_property: Restore the arguments of the next level parent
  2025-07-04 16:14 ` [PATCH v3 3/9] PCI: of_property: Restore the arguments of the next level parent Claudiu
@ 2025-08-20 17:47   ` Manivannan Sadhasivam
  2025-08-21  7:40     ` Claudiu Beznea
  0 siblings, 1 reply; 47+ messages in thread
From: Manivannan Sadhasivam @ 2025-08-20 17:47 UTC (permalink / raw)
  To: Claudiu
  Cc: bhelgaas, lpieralisi, kwilczynski, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou, linux-pci, linux-renesas-soc,
	devicetree, linux-kernel, linux-arm-kernel, linux-clk,
	Claudiu Beznea

On Fri, Jul 04, 2025 at 07:14:03PM GMT, Claudiu wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> 
> of_pci_make_dev_node() creates a device tree node for the PCIe bridge it
> detects. The node name follows the format: pci_type@pci_slot,pci_func. If
> such a node already exists in the current device tree, a new one is not
> created.
> 
> When the node is created, its contents are populated with information from
> the parent node. In the case of root complex nodes described in the device
> tree, the created node duplicates the interrupt-map property. However, the
> duplicated interrupt-map property does not correctly point to the next
> interrupt controller.
> 
> For example, in the case of the Renesas RZ/G3S SoC, the resulting device
> tree node is as follows (only relevant DT properties are shown):
> 
> pcie@11e40000 {
> 
>     // ...
> 
>     interrupt-map = <0x00 0x00 0x00 0x01 0x1f 0x00 0x00 0x00 0x00
>                      0x00 0x00 0x00 0x02 0x1f 0x00 0x00 0x00 0x01
>                      0x00 0x00 0x00 0x03 0x1f 0x00 0x00 0x00 0x02
>                      0x00 0x00 0x00 0x04 0x1f 0x00 0x00 0x00 0x03>;
>     interrupt-map-mask = <0x00 0x00 0x00 0x07>;
>     interrupt-controller;
>     #interrupt-cells = <0x01>;
> 
>     #address-cells = <0x03>;
>     #size-cells = <0x02>;
> 
>     phandle = <0x1f>;
> 
>     // ...
> 
>     pci@0,0 {
>         reg = <0x00 0x00 0x00 0x00 0x00>;
>         interrupt-map = <0x10000 0x00 0x00 0x01 0x1f 0x00 0x11e40000 0x00 0x00
>                          0x10000 0x00 0x00 0x02 0x1f 0x00 0x11e40000 0x00 0x01
>                          0x10000 0x00 0x00 0x03 0x1f 0x00 0x11e40000 0x00 0x02
>                          0x10000 0x00 0x00 0x04 0x1f 0x00 0x11e40000 0x00 0x03>;
>         interrupt-map-mask = <0xffff00 0x00 0x00 0x07>;
>         #interrupt-cells = <0x01>;
> 
>         #address-cells = <0x03>;
>         #size-cells = <0x02>;
> 
>         // ...
>     };
> };
> 
> With this pci@0,0 node, the interrupt-map parsing code behaves as follows:
> 
> When a PCIe endpoint is enumerated and it requests to map a legacy
> interrupt, of_irq_parse_raw() is called requesting the interrupt from
> pci@0,0. If INTA is requested, of_irq_parse_raw() first matches:
> 
> interrupt-map = <0x10000 0x00 0x00 0x01 0x1f 0x00 0x11e40000 0x00 0x00>
> 
> from the pci@0,0 node. It then follows the phandle 0x1f to the interrupt
> parent, looking for a mapping for interrupt ID 0x00
> (0x00 0x11e40000 0x00 0x00). However, the root complex node does not
> provide this mapping in its interrupt-map property, causing the interrupt
> request to fail.
> 

Are you trying to say that the generated bridge node incorrectly uses Root
Complex node as the interrupt parent?

I'm getting confused since your example above shows '0x1f' as the interrupt
parent phandle for both Root Complex and bridge nodes. But I don't know to which
node this phandle corresponds to.

In any case, since this seems to be an independent fix, please send it
separately.

- Mani

> To avoid this, in the interrupt-map property of the nodes generated by
> of_pci_make_dev_node() map legacy interrupts to entries that are valid in
> the next level interrupt controller in the interrupt mapping tree.
> 
> With this, the generated pci@0,0 node and its parent look as follows:
> 
> pcie@11e40000 {
>     // ...
> 
>     interrupt-map = <0x00 0x00 0x00 0x01 0x1f 0x00 0x00 0x00 0x00
>                      0x00 0x00 0x00 0x02 0x1f 0x00 0x00 0x00 0x01
>                      0x00 0x00 0x00 0x03 0x1f 0x00 0x00 0x00 0x02
>                      0x00 0x00 0x00 0x04 0x1f 0x00 0x00 0x00 0x03>;
>     interrupt-map-mask = <0x00 0x00 0x00 0x07>;
>     interrupt-controller;
>     #interrupt-cells = <0x01>;
> 
>     #address-cells = <0x03>;
>     #size-cells = <0x02>;
> 
>     phandle = <0x1f>;
> 
>     // ...
> 
>     pci@0,0 {
>         reg = <0x00 0x00 0x00 0x00 0x00>;
>         interrupt-map = <0x10000 0x00 0x00 0x01 0x1f 0x00 0x11e40000 0x00 0x01
>                          0x10000 0x00 0x00 0x02 0x1f 0x00 0x11e40000 0x00 0x02
>                          0x10000 0x00 0x00 0x03 0x1f 0x00 0x11e40000 0x00 0x03
>                          0x10000 0x00 0x00 0x04 0x1f 0x00 0x11e40000 0x00 0x04>;
>         interrupt-map-mask = <0xffff00 0x00 0x00 0x07>;
>         #interrupt-cells = <0x01>;
> 
>         #address-cells = <0x03>;
>         #size-cells = <0x02>;
>     };
> };
> 
> Fixes: 407d1a51921e ("PCI: Create device tree node for bridge")
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---
> 
> Changes in v3:
> - none; this patch is new
> 
>  drivers/pci/of_property.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/drivers/pci/of_property.c b/drivers/pci/of_property.c
> index 506fcd507113..8dfed096326f 100644
> --- a/drivers/pci/of_property.c
> +++ b/drivers/pci/of_property.c
> @@ -243,6 +243,14 @@ static int of_pci_prop_intr_map(struct pci_dev *pdev, struct of_changeset *ocs,
>  		}
>  		of_property_read_u32(out_irq[i].np, "#address-cells",
>  				     &addr_sz[i]);
> +
> +		/*
> +		 * Restore the arguments of the next level parent if a map
> +		 * was found.
> +		 */
> +		out_irq[i].np = pnode;
> +		out_irq[i].args_count = 1;
> +		out_irq[i].args[0] = pin;
>  	}
>  
>  	list_for_each_entry(child, &pdev->subordinate->devices, bus_list) {
> -- 
> 2.43.0
> 

-- 
மணிவண்ணன் சதாசிவம்


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

* Re: [PATCH v3 3/9] PCI: of_property: Restore the arguments of the next level parent
  2025-08-20 17:47   ` Manivannan Sadhasivam
@ 2025-08-21  7:40     ` Claudiu Beznea
  2025-08-30  4:10       ` Manivannan Sadhasivam
  0 siblings, 1 reply; 47+ messages in thread
From: Claudiu Beznea @ 2025-08-21  7:40 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: bhelgaas, lpieralisi, kwilczynski, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou, linux-pci, linux-renesas-soc,
	devicetree, linux-kernel, linux-arm-kernel, linux-clk,
	Claudiu Beznea

Hi, Manivannan,

On 20.08.2025 20:47, Manivannan Sadhasivam wrote:
> On Fri, Jul 04, 2025 at 07:14:03PM GMT, Claudiu wrote:
>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>>
>> of_pci_make_dev_node() creates a device tree node for the PCIe bridge it
>> detects. The node name follows the format: pci_type@pci_slot,pci_func. If
>> such a node already exists in the current device tree, a new one is not
>> created.
>>
>> When the node is created, its contents are populated with information from
>> the parent node. In the case of root complex nodes described in the device
>> tree, the created node duplicates the interrupt-map property. However, the
>> duplicated interrupt-map property does not correctly point to the next
>> interrupt controller.
>>
>> For example, in the case of the Renesas RZ/G3S SoC, the resulting device
>> tree node is as follows (only relevant DT properties are shown):
>>
>> pcie@11e40000 {
>>
>>     // ...
>>
>>     interrupt-map = <0x00 0x00 0x00 0x01 0x1f 0x00 0x00 0x00 0x00
>>                      0x00 0x00 0x00 0x02 0x1f 0x00 0x00 0x00 0x01
>>                      0x00 0x00 0x00 0x03 0x1f 0x00 0x00 0x00 0x02
>>                      0x00 0x00 0x00 0x04 0x1f 0x00 0x00 0x00 0x03>;
>>     interrupt-map-mask = <0x00 0x00 0x00 0x07>;
>>     interrupt-controller;
>>     #interrupt-cells = <0x01>;
>>
>>     #address-cells = <0x03>;
>>     #size-cells = <0x02>;
>>
>>     phandle = <0x1f>;
>>
>>     // ...
>>
>>     pci@0,0 {
>>         reg = <0x00 0x00 0x00 0x00 0x00>;
>>         interrupt-map = <0x10000 0x00 0x00 0x01 0x1f 0x00 0x11e40000 0x00 0x00
>>                          0x10000 0x00 0x00 0x02 0x1f 0x00 0x11e40000 0x00 0x01
>>                          0x10000 0x00 0x00 0x03 0x1f 0x00 0x11e40000 0x00 0x02
>>                          0x10000 0x00 0x00 0x04 0x1f 0x00 0x11e40000 0x00 0x03>;
>>         interrupt-map-mask = <0xffff00 0x00 0x00 0x07>;
>>         #interrupt-cells = <0x01>;
>>
>>         #address-cells = <0x03>;
>>         #size-cells = <0x02>;
>>
>>         // ...
>>     };
>> };
>>
>> With this pci@0,0 node, the interrupt-map parsing code behaves as follows:
>>
>> When a PCIe endpoint is enumerated and it requests to map a legacy
>> interrupt, of_irq_parse_raw() is called requesting the interrupt from
>> pci@0,0. If INTA is requested, of_irq_parse_raw() first matches:
>>
>> interrupt-map = <0x10000 0x00 0x00 0x01 0x1f 0x00 0x11e40000 0x00 0x00>
>>
>> from the pci@0,0 node. It then follows the phandle 0x1f to the interrupt
>> parent, looking for a mapping for interrupt ID 0x00
>> (0x00 0x11e40000 0x00 0x00). However, the root complex node does not
>> provide this mapping in its interrupt-map property, causing the interrupt
>> request to fail.
>>
> 
> Are you trying to say that the generated bridge node incorrectly uses Root
> Complex node as the interrupt parent?

I'm trying to say that the generated bridge node is wrong because it copies
the interrupt-map from the root complex mapping int 0x1 to 0x0 in the
bridge node, while it should have map the int 0x1 to something valid for
root complex mapping.

E.g. when some device requests INT with id 0x1 from bridge the bridge
mapping returns 0x0 then the returned 0x0 is used to find a new mapping on
the root complex based on what is provided for in with interrupt-map DT
property.


> 
> I'm getting confused since your example above shows '0x1f' as the interrupt
> parent phandle for both Root Complex and bridge nodes. But I don't know to which
> node this phandle corresponds to.

Root complex node from this patch description has:

phandle = <0x1f>;


> 
> In any case, since this seems to be an independent fix, please send it
> separately.

Yes, once port bindings are added this fix is not needed for this driver
anymore. Will post it as a separate fix.

Thank you,
Claudiu


> 
> - Mani
> 
>> To avoid this, in the interrupt-map property of the nodes generated by
>> of_pci_make_dev_node() map legacy interrupts to entries that are valid in
>> the next level interrupt controller in the interrupt mapping tree.
>>
>> With this, the generated pci@0,0 node and its parent look as follows:
>>
>> pcie@11e40000 {
>>     // ...
>>
>>     interrupt-map = <0x00 0x00 0x00 0x01 0x1f 0x00 0x00 0x00 0x00
>>                      0x00 0x00 0x00 0x02 0x1f 0x00 0x00 0x00 0x01
>>                      0x00 0x00 0x00 0x03 0x1f 0x00 0x00 0x00 0x02
>>                      0x00 0x00 0x00 0x04 0x1f 0x00 0x00 0x00 0x03>;
>>     interrupt-map-mask = <0x00 0x00 0x00 0x07>;
>>     interrupt-controller;
>>     #interrupt-cells = <0x01>;
>>
>>     #address-cells = <0x03>;
>>     #size-cells = <0x02>;
>>
>>     phandle = <0x1f>;
>>
>>     // ...
>>
>>     pci@0,0 {
>>         reg = <0x00 0x00 0x00 0x00 0x00>;
>>         interrupt-map = <0x10000 0x00 0x00 0x01 0x1f 0x00 0x11e40000 0x00 0x01
>>                          0x10000 0x00 0x00 0x02 0x1f 0x00 0x11e40000 0x00 0x02
>>                          0x10000 0x00 0x00 0x03 0x1f 0x00 0x11e40000 0x00 0x03
>>                          0x10000 0x00 0x00 0x04 0x1f 0x00 0x11e40000 0x00 0x04>;
>>         interrupt-map-mask = <0xffff00 0x00 0x00 0x07>;
>>         #interrupt-cells = <0x01>;
>>
>>         #address-cells = <0x03>;
>>         #size-cells = <0x02>;
>>     };
>> };
>>
>> Fixes: 407d1a51921e ("PCI: Create device tree node for bridge")
>> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>> ---
>>
>> Changes in v3:
>> - none; this patch is new
>>
>>  drivers/pci/of_property.c | 8 ++++++++
>>  1 file changed, 8 insertions(+)
>>
>> diff --git a/drivers/pci/of_property.c b/drivers/pci/of_property.c
>> index 506fcd507113..8dfed096326f 100644
>> --- a/drivers/pci/of_property.c
>> +++ b/drivers/pci/of_property.c
>> @@ -243,6 +243,14 @@ static int of_pci_prop_intr_map(struct pci_dev *pdev, struct of_changeset *ocs,
>>  		}
>>  		of_property_read_u32(out_irq[i].np, "#address-cells",
>>  				     &addr_sz[i]);
>> +
>> +		/*
>> +		 * Restore the arguments of the next level parent if a map
>> +		 * was found.
>> +		 */
>> +		out_irq[i].np = pnode;
>> +		out_irq[i].args_count = 1;
>> +		out_irq[i].args[0] = pin;
>>  	}
>>  
>>  	list_for_each_entry(child, &pdev->subordinate->devices, bus_list) {
>> -- 
>> 2.43.0
>>
> 



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

* Re: [PATCH v3 4/9] dt-bindings: PCI: renesas,r9a08g045s33-pcie: Add documentation for the PCIe IP on Renesas RZ/G3S
  2025-08-08 11:25     ` Claudiu Beznea
  2025-08-08 16:23       ` Bjorn Helgaas
@ 2025-08-28 19:11       ` claudiu beznea
  2025-08-28 19:36         ` Bjorn Helgaas
  1 sibling, 1 reply; 47+ messages in thread
From: claudiu beznea @ 2025-08-28 19:11 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou, linux-pci, linux-renesas-soc,
	devicetree, linux-kernel, linux-arm-kernel, linux-clk,
	Claudiu Beznea, Wolfram Sang

Hi, Bjorn,

On 8/8/25 14:25, Claudiu Beznea wrote:
> Hi, Bjorn,
> 
> On 08.07.2025 19:34, Bjorn Helgaas wrote:
>> On Fri, Jul 04, 2025 at 07:14:04PM +0300, Claudiu wrote:
>>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>>>
>>> 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 documentation for it.
>>
>>> +++ b/Documentation/devicetree/bindings/pci/renesas,r9a08g045s33-pcie.yaml
>>
>> The "r9a08g045s33" in the filename seems oddly specific.  Does it
>> leave room for descendants of the current chip that will inevitably be
>> added in the future?  Most bindings are named with a fairly generic
>> family name, e.g., "fsl,layerscape", "hisilicon,kirin", "intel,
>> keembay", "samsung,exynos", etc.
>>
>>> +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,r9a08g045s33-pcie";
>>> +            reg = <0 0x11e40000 0 0x10000>;
>>> +            ranges = <0x02000000 0 0x30000000 0 0x30000000 0 0x8000000>;
>>> +            dma-ranges = <0x42000000 0 0x48000000 0 0x48000000 0 0x38000000>;
>>> +            bus-range = <0x0 0xff>;
>>> +            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";
>>> +            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>, /* INT A */
>>> +                            <0 0 0 2 &pcie 0 0 0 1>, /* INT B */
>>> +                            <0 0 0 3 &pcie 0 0 0 2>, /* INT C */
>>> +                            <0 0 0 4 &pcie 0 0 0 3>; /* INT D */
>>
>> The spec styles these closed up: "INTA", "INTB", etc.
> 
> I'll update it.
> 
>>
>>> +            device_type = "pci";
>>> +            num-lanes = <1>;
>>> +            #address-cells = <3>;
>>> +            #size-cells = <2>;
>>> +            power-domains = <&cpg>;
>>> +            vendor-id = <0x1912>;
>>> +            device-id = <0x0033>;
>>
>> Some of this is specific to a Root Port, not to the Root Complex as a
>> whole.  E.g., device-type = "pci", num-lanes, vendor-id, device-id,
>> are Root Port properties.  Some of the resets, clocks, and interrupts
>> might be as well.
>>
>> I really want to separate those out because even though this
>> particular version of this PCIe controller only supports a single Root
>> Port, there are other controllers (and possibly future iterations of
>> this controller) that support multiple Root Ports, and it makes
>> maintenance easier if the DT bindings and the driver structures are
>> similar.
> 
> I'll ask the Renesas HW team about the resets and clocks as the HW manual
> don't offer any information about this.

Renesas HW team replied to me that there are no clock, reset, or interrupt 
signals dedicated specifically to the Root Port. All these signals are shared 
across the PCIe system.

Taking this and your suggestions into account, I have prepared the following 
device tree:

pcie: pcie@11e40000 {
	compatible = "renesas,r9a08g045-pcie";
	reg = <0 0x11e40000 0 0x10000>;
	ranges = <0x02000000 0 0x30000000 0 0x30000000 0 0x8000000>;
	/* Map all possible DRAM ranges (4 GB). */
	dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0x1 0x0>;
	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;
		clocks = <&versa3 5>;
		clock-names = "ref";
		device_type = "pci";
		vendor-id = <0x1912>;
		device-id = <0x0033>;
		bus-range = <0x1 0xff>;
		#address-cells = <3>;
		#size-cells = <2>;
	};
};

and added clocks in the port section, populated with the reference clock that is 
provided by a board specific clock generator (that I failed to noticed 
previously on schematics; this clock is always on).

Please let me know if you find something wrong with this format.

Thank you,
Claudiu


> 
> If they will confirm some of the clocks and/or resets could be controlled
> as part of a port then patch 3/9 "PCI: of_property: Restore the arguments
> of the next level parent" in this series will not be needed anymore. Would
> you prefer me to abandon it or post it as individual patch, if any?
> 
>>
>> This email includes pointers to sample DT bindings and driver code
>> that is structured to allow multiple Root Ports:
>>
>>    https://lore.kernel.org/linux-pci/20250625221653.GA1590146@bhelgaas/
> 
> Thank you for this!
> 
> And, thank you for your review,
> Claudiu
> 
>>
>> Bjorn
> 



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

* Re: [PATCH v3 4/9] dt-bindings: PCI: renesas,r9a08g045s33-pcie: Add documentation for the PCIe IP on Renesas RZ/G3S
  2025-08-28 19:11       ` claudiu beznea
@ 2025-08-28 19:36         ` Bjorn Helgaas
  2025-08-29  5:03           ` claudiu beznea
  0 siblings, 1 reply; 47+ messages in thread
From: Bjorn Helgaas @ 2025-08-28 19:36 UTC (permalink / raw)
  To: claudiu beznea
  Cc: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou, linux-pci, linux-renesas-soc,
	devicetree, linux-kernel, linux-arm-kernel, linux-clk,
	Claudiu Beznea, Wolfram Sang

On Thu, Aug 28, 2025 at 10:11:55PM +0300, claudiu beznea wrote:
> On 8/8/25 14:25, Claudiu Beznea wrote:
> > On 08.07.2025 19:34, Bjorn Helgaas wrote:
> > > On Fri, Jul 04, 2025 at 07:14:04PM +0300, Claudiu wrote:
> > > > From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> > > > 
> > > > 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 documentation for it.
> ...

> Renesas HW team replied to me that there are no clock, reset, or interrupt
> signals dedicated specifically to the Root Port. All these signals are
> shared across the PCIe system.
> 
> Taking this and your suggestions into account, I have prepared the following
> device tree:
> 
> pcie: pcie@11e40000 {
> 	compatible = "renesas,r9a08g045-pcie";
> 	reg = <0 0x11e40000 0 0x10000>;
> 	ranges = <0x02000000 0 0x30000000 0 0x30000000 0 0x8000000>;
> 	/* Map all possible DRAM ranges (4 GB). */
> 	dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0x1 0x0>;
> 	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;
> 		clocks = <&versa3 5>;
> 		clock-names = "ref";
> 		device_type = "pci";
> 		vendor-id = <0x1912>;
> 		device-id = <0x0033>;
> 		bus-range = <0x1 0xff>;

I don't think you need this bus-range.  The bus range for the
hierarchy below a Root Port is discoverable and configurable via
config space.

> 		#address-cells = <3>;
> 		#size-cells = <2>;
> 	};
> };


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

* Re: [PATCH v3 4/9] dt-bindings: PCI: renesas,r9a08g045s33-pcie: Add documentation for the PCIe IP on Renesas RZ/G3S
  2025-08-28 19:36         ` Bjorn Helgaas
@ 2025-08-29  5:03           ` claudiu beznea
  0 siblings, 0 replies; 47+ messages in thread
From: claudiu beznea @ 2025-08-29  5:03 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: bhelgaas, lpieralisi, kwilczynski, mani, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou, linux-pci, linux-renesas-soc,
	devicetree, linux-kernel, linux-arm-kernel, linux-clk,
	Claudiu Beznea, Wolfram Sang

Hi, Bjorn,

On 8/28/25 22:36, Bjorn Helgaas wrote:
> On Thu, Aug 28, 2025 at 10:11:55PM +0300, claudiu beznea wrote:
>> On 8/8/25 14:25, Claudiu Beznea wrote:
>>> On 08.07.2025 19:34, Bjorn Helgaas wrote:
>>>> On Fri, Jul 04, 2025 at 07:14:04PM +0300, Claudiu wrote:
>>>>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>>>>>
>>>>> 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 documentation for it.
>> ...
> 
>> Renesas HW team replied to me that there are no clock, reset, or interrupt
>> signals dedicated specifically to the Root Port. All these signals are
>> shared across the PCIe system.
>>
>> Taking this and your suggestions into account, I have prepared the following
>> device tree:
>>
>> pcie: pcie@11e40000 {
>> 	compatible = "renesas,r9a08g045-pcie";
>> 	reg = <0 0x11e40000 0 0x10000>;
>> 	ranges = <0x02000000 0 0x30000000 0 0x30000000 0 0x8000000>;
>> 	/* Map all possible DRAM ranges (4 GB). */
>> 	dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0x1 0x0>;
>> 	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;
>> 		clocks = <&versa3 5>;
>> 		clock-names = "ref";
>> 		device_type = "pci";
>> 		vendor-id = <0x1912>;
>> 		device-id = <0x0033>;
>> 		bus-range = <0x1 0xff>;
> 
> I don't think you need this bus-range.  The bus range for the
> hierarchy below a Root Port is discoverable and configurable via
> config space.

Thank you for the pointer. I'll update and send a new version.

Claudiu




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

* Re: [PATCH v3 3/9] PCI: of_property: Restore the arguments of the next level parent
  2025-08-21  7:40     ` Claudiu Beznea
@ 2025-08-30  4:10       ` Manivannan Sadhasivam
  0 siblings, 0 replies; 47+ messages in thread
From: Manivannan Sadhasivam @ 2025-08-30  4:10 UTC (permalink / raw)
  To: Claudiu Beznea
  Cc: bhelgaas, lpieralisi, kwilczynski, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou, linux-pci, linux-renesas-soc,
	devicetree, linux-kernel, linux-arm-kernel, linux-clk,
	Claudiu Beznea

On Thu, Aug 21, 2025 at 10:40:40AM GMT, Claudiu Beznea wrote:
> Hi, Manivannan,
> 
> On 20.08.2025 20:47, Manivannan Sadhasivam wrote:
> > On Fri, Jul 04, 2025 at 07:14:03PM GMT, Claudiu wrote:
> >> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> >>
> >> of_pci_make_dev_node() creates a device tree node for the PCIe bridge it
> >> detects. The node name follows the format: pci_type@pci_slot,pci_func. If
> >> such a node already exists in the current device tree, a new one is not
> >> created.
> >>
> >> When the node is created, its contents are populated with information from
> >> the parent node. In the case of root complex nodes described in the device
> >> tree, the created node duplicates the interrupt-map property. However, the
> >> duplicated interrupt-map property does not correctly point to the next
> >> interrupt controller.
> >>
> >> For example, in the case of the Renesas RZ/G3S SoC, the resulting device
> >> tree node is as follows (only relevant DT properties are shown):
> >>
> >> pcie@11e40000 {
> >>
> >>     // ...
> >>
> >>     interrupt-map = <0x00 0x00 0x00 0x01 0x1f 0x00 0x00 0x00 0x00
> >>                      0x00 0x00 0x00 0x02 0x1f 0x00 0x00 0x00 0x01
> >>                      0x00 0x00 0x00 0x03 0x1f 0x00 0x00 0x00 0x02
> >>                      0x00 0x00 0x00 0x04 0x1f 0x00 0x00 0x00 0x03>;
> >>     interrupt-map-mask = <0x00 0x00 0x00 0x07>;
> >>     interrupt-controller;
> >>     #interrupt-cells = <0x01>;
> >>
> >>     #address-cells = <0x03>;
> >>     #size-cells = <0x02>;
> >>
> >>     phandle = <0x1f>;
> >>
> >>     // ...
> >>
> >>     pci@0,0 {
> >>         reg = <0x00 0x00 0x00 0x00 0x00>;
> >>         interrupt-map = <0x10000 0x00 0x00 0x01 0x1f 0x00 0x11e40000 0x00 0x00
> >>                          0x10000 0x00 0x00 0x02 0x1f 0x00 0x11e40000 0x00 0x01
> >>                          0x10000 0x00 0x00 0x03 0x1f 0x00 0x11e40000 0x00 0x02
> >>                          0x10000 0x00 0x00 0x04 0x1f 0x00 0x11e40000 0x00 0x03>;
> >>         interrupt-map-mask = <0xffff00 0x00 0x00 0x07>;
> >>         #interrupt-cells = <0x01>;
> >>
> >>         #address-cells = <0x03>;
> >>         #size-cells = <0x02>;
> >>
> >>         // ...
> >>     };
> >> };
> >>
> >> With this pci@0,0 node, the interrupt-map parsing code behaves as follows:
> >>
> >> When a PCIe endpoint is enumerated and it requests to map a legacy
> >> interrupt, of_irq_parse_raw() is called requesting the interrupt from
> >> pci@0,0. If INTA is requested, of_irq_parse_raw() first matches:
> >>
> >> interrupt-map = <0x10000 0x00 0x00 0x01 0x1f 0x00 0x11e40000 0x00 0x00>
> >>
> >> from the pci@0,0 node. It then follows the phandle 0x1f to the interrupt
> >> parent, looking for a mapping for interrupt ID 0x00
> >> (0x00 0x11e40000 0x00 0x00). However, the root complex node does not
> >> provide this mapping in its interrupt-map property, causing the interrupt
> >> request to fail.
> >>
> > 
> > Are you trying to say that the generated bridge node incorrectly uses Root
> > Complex node as the interrupt parent?
> 
> I'm trying to say that the generated bridge node is wrong because it copies
> the interrupt-map from the root complex mapping int 0x1 to 0x0 in the
> bridge node, while it should have map the int 0x1 to something valid for
> root complex mapping.
> 
> E.g. when some device requests INT with id 0x1 from bridge the bridge
> mapping returns 0x0 then the returned 0x0 is used to find a new mapping on
> the root complex based on what is provided for in with interrupt-map DT
> property.
> 

TBH, I don't know why it generates the 'interrupt-map' property for the bridge
node first place. It just creates two level lookup and in the absence, the IRQ
code will traverse up the node to find the interrupt parent anyway.

Maybe the intention was to avoid doing the traversal.

> 
> > 
> > I'm getting confused since your example above shows '0x1f' as the interrupt
> > parent phandle for both Root Complex and bridge nodes. But I don't know to which
> > node this phandle corresponds to.
> 
> Root complex node from this patch description has:
> 
> phandle = <0x1f>;
> 

Oops. I failed to spot it.

- Mani

-- 
மணிவண்ணன் சதாசிவம்


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

* Re: [PATCH v3 5/9] PCI: rzg3s-host: Add Initial PCIe Host Driver for Renesas RZ/G3S SoC
  2025-07-04 16:14 ` [PATCH v3 5/9] PCI: rzg3s-host: Add Initial PCIe Host Driver for Renesas RZ/G3S SoC Claudiu
  2025-07-08 19:24   ` Bjorn Helgaas
@ 2025-08-30  6:59   ` Manivannan Sadhasivam
  2025-08-30 11:22     ` Claudiu Beznea
  1 sibling, 1 reply; 47+ messages in thread
From: Manivannan Sadhasivam @ 2025-08-30  6:59 UTC (permalink / raw)
  To: Claudiu
  Cc: bhelgaas, lpieralisi, kwilczynski, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou, linux-pci, linux-renesas-soc,
	devicetree, linux-kernel, linux-arm-kernel, linux-clk,
	Claudiu Beznea, Wolfram Sang

On Fri, Jul 04, 2025 at 07:14:05PM GMT, Claudiu wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> 
> 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
> 
> Link: https://www.renesas.com/en/products/rz-g3s?queryID=695cc067c2d89e3f271d43656ede4d12
> Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---
> 

[...]

> +static bool 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);
> +
> +	return !!ret || (val & RZG3S_PCI_REQISS_MOR_STATUS);

You don't need to do !!ret as the C11 standard guarantees that any scalar type
stored as bool will have the value of 0 or 1.

> +}
> +

[...]

> +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;

Is it really possible to have devfn as non-zero for a root bus?

> +
> +	return host->pcie + where;
> +}
> +

[...]

> +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 need to be within any AXI window. Find
> +	 * an AXI window to setup the MSI window.

Are you really finding the AXI window or just making sure that the MSI window
falls into one of the AXI window?

And I believe it is OK to have more than one MSI window within an AXI window.

> +	 */
> +	for (id = 0; id < RZG3S_MAX_WINDOWS; id++) {
> +		u64 base, basel, baseu;
> +		u64 mask, maskl, masku;
> +
> +		basel = readl(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(host->axi + RZG3S_PCI_AWBASEU(id));
> +		base = baseu << 32 | basel;
> +
> +		maskl = readl(host->axi + RZG3S_PCI_AWMASKL(id));
> +		masku = readl(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 need to 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 int rzg3s_pcie_set_max_link_speed(struct rzg3s_pcie_host *host)
> +{
> +	u32 cs2, link_speed, remote_supported_link_speeds, tmp;
> +	u32 pcie_cap = RZG3S_PCI_CFG_PCIEC;
> +	u8 ltssm_state_l0 = 0xc;
> +	u16 lcs;
> +	int ret;
> +
> +	/*
> +	 * 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 link training and status state machine in the PCIe Core
> +	 * Link is L0.

"...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,
> +				 PCIE_LINK_WAIT_SLEEP_MS *
> +				 PCIE_LINK_WAIT_MAX_RETRIES * MILLI);
> +	if (ret) {
> +		dev_dbg(host->dev,
> +			"Could not set max link speed! LTSSM not in L0, state=%lx\n",

You should drop 'Could not set max link speed' since the caller is printing a
similar error.

> +			FIELD_GET(RZG3S_PCI_PCSTAT1_LTSSM_STATE, tmp));
> +		return ret;
> +	}
> +
> +	lcs = readw(host->pcie + pcie_cap + PCI_EXP_LNKSTA);
> +	cs2 = readl(host->axi + RZG3S_PCI_PCSTAT2);
> +
> +	link_speed = FIELD_GET(PCI_EXP_LNKSTA_CLS, lcs);
> +	remote_supported_link_speeds = FIELD_GET(RZG3S_PCI_PCSTAT2_SDRIRE, cs2);
> +
> +	/*
> +	 * Return if link is @ 5.0 GT/s or the connected device doesn't support
> +	 * it.
> +	 */
> +	if (link_speed == PCI_EXP_LNKSTA_CLS_5_0GB ||
> +	    !(remote_supported_link_speeds != GENMASK(PCI_EXP_LNKSTA_CLS_5_0GB - 1, 0)))
> +		return 0;
> +
> +	/* Set target Link speed to 5.0 GT/s */

Instead of setting the link speed to 5 GT/s always, you should honor the link
speed set in DTS by making use of of_pci_get_max_link_speed() API.

> +	rzg3s_pcie_update_bits(host->pcie, pcie_cap + PCI_EXP_LNKCTL2,
> +			       PCI_EXP_LNKCTL2_TLS,
> +			       FIELD_PREP(PCI_EXP_LNKCTL2_TLS,
> +					  PCI_EXP_LNKCTL2_TLS_5_0GT));
> +
> +	/* 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,
> +					  PCI_EXP_LNKCTL2_TLS_5_0GT - 1));
> +
> +	ret = readl_poll_timeout(host->axi + RZG3S_PCI_PCSTAT2, cs2,
> +				 (cs2 & RZG3S_PCI_PCSTAT2_LS_CHG_DONE),
> +				 PCIE_LINK_WAIT_SLEEP_MS,
> +				 PCIE_LINK_WAIT_SLEEP_MS *
> +				 PCIE_LINK_WAIT_MAX_RETRIES * MILLI);
> +
> +	/*
> +	 * 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(RZG3S_PCI_PERM_CFG_HWINIT_EN, host->axi + RZG3S_PCI_PERM);
> +
> +	/* Update vendor ID and device ID */

Are you really updating it or setting it? If you are updating it, are the
default IDs invalid?

> +	writew(host->vendor_id, host->pcie + PCI_VENDOR_ID);
> +	writew(host->device_id, host->pcie + PCI_DEVICE_ID);
> +
> +	/* HW manual recommends to write 0xffffffff on initialization */
> +	writel(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00L);
> +	writel(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00U);
> +
> +	/* Update bus info. */
> +	writeb(primary_bus, host->pcie + PCI_PRIMARY_BUS);
> +	writeb(secondary_bus, host->pcie + PCI_SECONDARY_BUS);
> +	writeb(subordinate_bus, host->pcie + PCI_SUBORDINATE_BUS);
> +
> +	/* Disable access control to the CFGU */
> +	writel(0, host->axi + RZG3S_PCI_PERM);
> +
> +	return 0;
> +}
> +

[...]

> +static int rzg3s_pcie_host_init(struct rzg3s_pcie_host *host, bool probe)
> +{
> +	u32 val;
> +	int ret;
> +
> +	/* Initialize the PCIe related registers */
> +	ret = rzg3s_pcie_config_init(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)
> +		return ret;
> +
> +	/* 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,
> +				 PCIE_LINK_WAIT_SLEEP_MS *
> +				 PCIE_LINK_WAIT_MAX_RETRIES * MILLI);
> +	if (ret) {
> +		reset_control_bulk_assert(host->data->num_cfg_resets,
> +					  host->cfg_resets);
> +		return ret;
> +	}
> +
> +	val = readl(host->axi + RZG3S_PCI_PCSTAT2);
> +	dev_info(host->dev, "PCIe link status [0x%x]\n", val);
> +
> +	val = FIELD_GET(RZG3S_PCI_PCSTAT2_STATE_RX_DETECT, val);
> +	dev_info(host->dev, "PCIe x%d: link up\n", hweight32(val));
> +
> +	if (probe) {
> +		ret = devm_add_action_or_reset(host->dev,
> +					       rzg3s_pcie_cfg_resets_action,
> +					       host);

Oh well, this gets ugly. Now the devm_add_action_or_reset() is sprinkled
throughout the driver :/

As I said earlier, there are concerns in unloading the driver if it implements
an irqchip. So if you change the module_platform_driver() to
builtin_platform_driver() for this driver, these devm_add_action_or_reset()
calls become unused.

> +	}
> +
> +	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(upper_32_bits(cpu_addr), host->axi + RZG3S_PCI_ADESTU(id));
> +	writel(lower_32_bits(cpu_addr), host->axi + RZG3S_PCI_ADESTL(id));
> +
> +	/* Set window size */
> +	writel(upper_32_bits(size), host->axi + RZG3S_PCI_AWMASKU(id));
> +	writel(lower_32_bits(size), host->axi + RZG3S_PCI_AWMASKL(id));
> +
> +	/* Set PCIe window base address and enable the window */
> +	writel(upper_32_bits(pci_addr), host->axi + RZG3S_PCI_AWBASEU(id));
> +	writel(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, -EINVAL,

-ENOSPC

> +					     "Failed to set inbound windows!\n");

"Failed to map inbound window for resource (%s), 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);
> +
> +		/*
> +		 * 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.
> +		 */
> +		size = roundup_pow_of_two(size) - 1;
> +
> +		cpu_addr = ALIGN(cpu_addr, SZ_4K);
> +		pci_addr = ALIGN(pci_addr, SZ_4K);
> +
> +		rzg3s_pcie_set_inbound_window(host, cpu_addr, pci_addr, size,
> +					      id);
> +
> +		pci_addr += size;
> +		cpu_addr += size;
> +		size_id = size;
> +		id++;
> +	}
> +	*index = id;
> +
> +	return 0;
> +}

[...]

> +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, -EINVAL,

-ENOSPC

> +					     "Failed to set outbound windows!\n");

"Failed to map outbound window for resource (%s), 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_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;
> +
> +	ret = of_property_read_u32(np, "vendor-id", &host->vendor_id);
> +	if (ret)
> +		return ret;
> +
> +	ret = of_property_read_u32(np, "device-id", &host->device_id);
> +	if (ret)
> +		return ret;
> +
> +	host->sysc = syscon_node_to_regmap(sysc_np);
> +	if (IS_ERR(host->sysc))
> +		return PTR_ERR(host->sysc);
> +
> +	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)
> +		return ret;
> +
> +	ret = devm_add_action_or_reset(dev, rzg3s_pcie_sysc_signal_action,
> +				       host->sysc);
> +	if (ret)
> +		return ret;
> +
> +	ret = rzg3s_pcie_resets_prepare(host);
> +	if (ret)
> +		return ret;
> +
> +	ret = devm_pm_runtime_enable(dev);
> +	if (ret)
> +		return ret;
> +
> +	ret = pm_runtime_resume_and_get(dev);
> +	if (ret)
> +		return ret;
> +

Do you really need to do resume_and_get()? If not, you should do:

	pm_runtime_set_active()
	pm_runtime_no_callbacks()
	devm_pm_runtime_enable()

> +	ret = devm_add_action_or_reset(dev, rzg3s_pcie_pm_runtime_put, dev);
> +	if (ret)
> +		return ret;
> +
> +	raw_spin_lock_init(&host->hw_lock);
> +
> +	ret = rzg3s_pcie_host_setup(host, rzg3s_pcie_intx_setup,
> +				    rzg3s_pcie_msi_enable, true);
> +	if (ret)
> +		return ret;
> +
> +	msleep(PCIE_RESET_CONFIG_WAIT_MS);
> +
> +	bridge->sysdata = host;
> +	bridge->ops = &rzg3s_pcie_root_ops;
> +	bridge->child_ops = &rzg3s_pcie_child_ops;
> +	ret = pci_host_probe(bridge);
> +	if (ret)
> +		return ret;
> +
> +	return devm_add_action_or_reset(dev, rzg3s_pcie_host_remove_action,
> +					host);
> +}
> +
> +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 regmap *sysc = host->sysc;
> +	int ret;
> +
> +	ret = pm_runtime_put_sync(dev);
> +	if (ret)
> +		return ret;

Since there are no runtime callbacks present, managing runtime PM in the driver
makes no sense.

> +
> +	ret = reset_control_bulk_assert(data->num_power_resets,
> +					host->power_resets);
> +	if (ret)
> +		goto rpm_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);
> +rpm_restore:
> +	pm_runtime_resume_and_get(dev);
> +	return ret;
> +}
> +

[...]

> +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 = rzg3s_pcie_probe,
> +};
> +module_platform_driver(rzg3s_pcie_driver);

Use builtin_platform_driver() as this driver is not supposed to be removed due
to concersn with irqchip.

- Mani

-- 
மணிவண்ணன் சதாசிவம்


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

* Re: [PATCH v3 5/9] PCI: rzg3s-host: Add Initial PCIe Host Driver for Renesas RZ/G3S SoC
  2025-08-30  6:59   ` Manivannan Sadhasivam
@ 2025-08-30 11:22     ` Claudiu Beznea
  2025-08-31  4:07       ` Manivannan Sadhasivam
  0 siblings, 1 reply; 47+ messages in thread
From: Claudiu Beznea @ 2025-08-30 11:22 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: bhelgaas, lpieralisi, kwilczynski, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou, linux-pci, linux-renesas-soc,
	devicetree, linux-kernel, linux-arm-kernel, linux-clk,
	Claudiu Beznea, Wolfram Sang



On 30.08.2025 09:59, Manivannan Sadhasivam wrote:
> On Fri, Jul 04, 2025 at 07:14:05PM GMT, Claudiu wrote:
>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>>
>> 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
>>
>> Link: https://www.renesas.com/en/products/rz-g3s?queryID=695cc067c2d89e3f271d43656ede4d12
>> Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
>> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>> ---
>>
> 
> [...]
> 
>> +static bool 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);
>> +
>> +	return !!ret || (val & RZG3S_PCI_REQISS_MOR_STATUS);
> 
> You don't need to do !!ret as the C11 standard guarantees that any scalar type
> stored as bool will have the value of 0 or 1.

OK, will drop it anyway as suggested in another thread.

> 
>> +}
>> +
> 
> [...]
> 
>> +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;
> 
> Is it really possible to have devfn as non-zero for a root bus?

I will drop it.

> 
>> +
>> +	return host->pcie + where;
>> +}
>> +
> 
> [...]
> 
>> +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 need to be within any AXI window. Find
>> +	 * an AXI window to setup the MSI window.
> 
> Are you really finding the AXI window or just making sure that the MSI window
> falls into one of the AXI window?

I'm making sure the MSI windows falls into one of the enabled AXI windows.

> 
> And I believe it is OK to have more than one MSI window within an AXI window.

This IP supports a single MSI window that need to fit into one of the
enabled AXI windows.

> 
>> +	 */
>> +	for (id = 0; id < RZG3S_MAX_WINDOWS; id++) {
>> +		u64 base, basel, baseu;
>> +		u64 mask, maskl, masku;
>> +
>> +		basel = readl(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(host->axi + RZG3S_PCI_AWBASEU(id));
>> +		base = baseu << 32 | basel;
>> +
>> +		maskl = readl(host->axi + RZG3S_PCI_AWMASKL(id));
>> +		masku = readl(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 need to 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 int rzg3s_pcie_set_max_link_speed(struct rzg3s_pcie_host *host)
>> +{
>> +	u32 cs2, link_speed, remote_supported_link_speeds, tmp;
>> +	u32 pcie_cap = RZG3S_PCI_CFG_PCIEC;
>> +	u8 ltssm_state_l0 = 0xc;
>> +	u16 lcs;
>> +	int ret;
>> +
>> +	/*
>> +	 * 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 link training and status state machine in the PCIe Core
>> +	 * Link is L0.
> 
> "...only when the LTSSM is in L0."

Ok

> 
>> +	 */
>> +	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,
>> +				 PCIE_LINK_WAIT_SLEEP_MS *
>> +				 PCIE_LINK_WAIT_MAX_RETRIES * MILLI);
>> +	if (ret) {
>> +		dev_dbg(host->dev,
>> +			"Could not set max link speed! LTSSM not in L0, state=%lx\n",
> 
> You should drop 'Could not set max link speed' since the caller is printing a
> similar error.

Ok, I'll drop.

> 
>> +			FIELD_GET(RZG3S_PCI_PCSTAT1_LTSSM_STATE, tmp));
>> +		return ret;
>> +	}
>> +
>> +	lcs = readw(host->pcie + pcie_cap + PCI_EXP_LNKSTA);
>> +	cs2 = readl(host->axi + RZG3S_PCI_PCSTAT2);
>> +
>> +	link_speed = FIELD_GET(PCI_EXP_LNKSTA_CLS, lcs);
>> +	remote_supported_link_speeds = FIELD_GET(RZG3S_PCI_PCSTAT2_SDRIRE, cs2);
>> +
>> +	/*
>> +	 * Return if link is @ 5.0 GT/s or the connected device doesn't support
>> +	 * it.
>> +	 */
>> +	if (link_speed == PCI_EXP_LNKSTA_CLS_5_0GB ||
>> +	    !(remote_supported_link_speeds != GENMASK(PCI_EXP_LNKSTA_CLS_5_0GB - 1, 0)))
>> +		return 0;
>> +
>> +	/* Set target Link speed to 5.0 GT/s */
> 
> Instead of setting the link speed to 5 GT/s always, you should honor the link
> speed set in DTS by making use of of_pci_get_max_link_speed() API.

Will check it.

> 
>> +	rzg3s_pcie_update_bits(host->pcie, pcie_cap + PCI_EXP_LNKCTL2,
>> +			       PCI_EXP_LNKCTL2_TLS,
>> +			       FIELD_PREP(PCI_EXP_LNKCTL2_TLS,
>> +					  PCI_EXP_LNKCTL2_TLS_5_0GT));
>> +
>> +	/* 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,
>> +					  PCI_EXP_LNKCTL2_TLS_5_0GT - 1));
>> +
>> +	ret = readl_poll_timeout(host->axi + RZG3S_PCI_PCSTAT2, cs2,
>> +				 (cs2 & RZG3S_PCI_PCSTAT2_LS_CHG_DONE),
>> +				 PCIE_LINK_WAIT_SLEEP_MS,
>> +				 PCIE_LINK_WAIT_SLEEP_MS *
>> +				 PCIE_LINK_WAIT_MAX_RETRIES * MILLI);
>> +
>> +	/*
>> +	 * 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(RZG3S_PCI_PERM_CFG_HWINIT_EN, host->axi + RZG3S_PCI_PERM);
>> +
>> +	/* Update vendor ID and device ID */
> 
> Are you really updating it or setting it? If you are updating it, are the
> default IDs invalid?

Default IDs are valid (at least on RZ/G3S) but Renesas specific. Renesas
wants to let individual users to set their own IDs.

> 
>> +	writew(host->vendor_id, host->pcie + PCI_VENDOR_ID);
>> +	writew(host->device_id, host->pcie + PCI_DEVICE_ID);
>> +
>> +	/* HW manual recommends to write 0xffffffff on initialization */
>> +	writel(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00L);
>> +	writel(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00U);
>> +
>> +	/* Update bus info. */
>> +	writeb(primary_bus, host->pcie + PCI_PRIMARY_BUS);
>> +	writeb(secondary_bus, host->pcie + PCI_SECONDARY_BUS);
>> +	writeb(subordinate_bus, host->pcie + PCI_SUBORDINATE_BUS);
>> +
>> +	/* Disable access control to the CFGU */
>> +	writel(0, host->axi + RZG3S_PCI_PERM);
>> +
>> +	return 0;
>> +}
>> +
> 
> [...]
> 
>> +static int rzg3s_pcie_host_init(struct rzg3s_pcie_host *host, bool probe)
>> +{
>> +	u32 val;
>> +	int ret;
>> +
>> +	/* Initialize the PCIe related registers */
>> +	ret = rzg3s_pcie_config_init(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)
>> +		return ret;
>> +
>> +	/* 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,
>> +				 PCIE_LINK_WAIT_SLEEP_MS *
>> +				 PCIE_LINK_WAIT_MAX_RETRIES * MILLI);
>> +	if (ret) {
>> +		reset_control_bulk_assert(host->data->num_cfg_resets,
>> +					  host->cfg_resets);
>> +		return ret;
>> +	}
>> +
>> +	val = readl(host->axi + RZG3S_PCI_PCSTAT2);
>> +	dev_info(host->dev, "PCIe link status [0x%x]\n", val);
>> +
>> +	val = FIELD_GET(RZG3S_PCI_PCSTAT2_STATE_RX_DETECT, val);
>> +	dev_info(host->dev, "PCIe x%d: link up\n", hweight32(val));
>> +
>> +	if (probe) {
>> +		ret = devm_add_action_or_reset(host->dev,
>> +					       rzg3s_pcie_cfg_resets_action,
>> +					       host);
> 
> Oh well, this gets ugly. Now the devm_add_action_or_reset() is sprinkled
> throughout the driver :/
> 
> As I said earlier, there are concerns in unloading the driver if it implements
> an irqchip. So if you change the module_platform_driver() to
> builtin_platform_driver() for this driver, these devm_add_action_or_reset()
> calls become unused.

They can still be useful in case the probe fails. As the initialization
path is complicated, having actions or resets looks to me that makes the
code cleaner as the rest of devm_* helpers.

I can drop it and replace with gotos and dedicated functions but this will
complicate the code, AFAICT.

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

> 
>> +	}
>> +
>> +	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(upper_32_bits(cpu_addr), host->axi + RZG3S_PCI_ADESTU(id));
>> +	writel(lower_32_bits(cpu_addr), host->axi + RZG3S_PCI_ADESTL(id));
>> +
>> +	/* Set window size */
>> +	writel(upper_32_bits(size), host->axi + RZG3S_PCI_AWMASKU(id));
>> +	writel(lower_32_bits(size), host->axi + RZG3S_PCI_AWMASKL(id));
>> +
>> +	/* Set PCIe window base address and enable the window */
>> +	writel(upper_32_bits(pci_addr), host->axi + RZG3S_PCI_AWBASEU(id));
>> +	writel(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, -EINVAL,
> 
> -ENOSPC
> 
>> +					     "Failed to set inbound windows!\n");
> 
> "Failed to map inbound window for resource (%s), entry->res->name"

Ok

> 
>> +
>> +		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);
>> +
>> +		/*
>> +		 * 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.
>> +		 */
>> +		size = roundup_pow_of_two(size) - 1;
>> +
>> +		cpu_addr = ALIGN(cpu_addr, SZ_4K);
>> +		pci_addr = ALIGN(pci_addr, SZ_4K);
>> +
>> +		rzg3s_pcie_set_inbound_window(host, cpu_addr, pci_addr, size,
>> +					      id);
>> +
>> +		pci_addr += size;
>> +		cpu_addr += size;
>> +		size_id = size;
>> +		id++;
>> +	}
>> +	*index = id;
>> +
>> +	return 0;
>> +}
> 
> [...]
> 
>> +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, -EINVAL,
> 
> -ENOSPC

Ok

> 
>> +					     "Failed to set outbound windows!\n");
> 
> "Failed to map outbound window for resource (%s), res->name"

Ok

> 
>> +
>> +		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_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;
>> +
>> +	ret = of_property_read_u32(np, "vendor-id", &host->vendor_id);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = of_property_read_u32(np, "device-id", &host->device_id);
>> +	if (ret)
>> +		return ret;
>> +
>> +	host->sysc = syscon_node_to_regmap(sysc_np);
>> +	if (IS_ERR(host->sysc))
>> +		return PTR_ERR(host->sysc);
>> +
>> +	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)
>> +		return ret;
>> +
>> +	ret = devm_add_action_or_reset(dev, rzg3s_pcie_sysc_signal_action,
>> +				       host->sysc);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = rzg3s_pcie_resets_prepare(host);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = devm_pm_runtime_enable(dev);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = pm_runtime_resume_and_get(dev);
>> +	if (ret)
>> +		return ret;
>> +
> 
> Do you really need to do resume_and_get()? If not, you should do:

It it's needed to enable the clock PM domain the device is part of.

> 
> 	pm_runtime_set_active()
> 	pm_runtime_no_callbacks()
> 	devm_pm_runtime_enable()
> 
>> +	ret = devm_add_action_or_reset(dev, rzg3s_pcie_pm_runtime_put, dev);
>> +	if (ret)
>> +		return ret;
>> +
>> +	raw_spin_lock_init(&host->hw_lock);
>> +
>> +	ret = rzg3s_pcie_host_setup(host, rzg3s_pcie_intx_setup,
>> +				    rzg3s_pcie_msi_enable, true);
>> +	if (ret)
>> +		return ret;
>> +
>> +	msleep(PCIE_RESET_CONFIG_WAIT_MS);
>> +
>> +	bridge->sysdata = host;
>> +	bridge->ops = &rzg3s_pcie_root_ops;
>> +	bridge->child_ops = &rzg3s_pcie_child_ops;
>> +	ret = pci_host_probe(bridge);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return devm_add_action_or_reset(dev, rzg3s_pcie_host_remove_action,
>> +					host);
>> +}
>> +
>> +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 regmap *sysc = host->sysc;
>> +	int ret;
>> +
>> +	ret = pm_runtime_put_sync(dev);
>> +	if (ret)
>> +		return ret;
> 
> Since there are no runtime callbacks present, managing runtime PM in the driver
> makes no sense.

The PCIe device is part of a clock power domain. Dropping
pm_runtime_enable()/pm_runtime_put_sync() in this driver will lead to this
IP failing to work as its clocks will not be enabled/disabled. If you don't
like the pm_runtime_* approach that could be replaced with:

devm_clk_get_enabled() in probe and clk_disable()/clk_enable() on
suspend/resume. W/o clocks the IP can't work.

Please let me know what approach is prefered here.


> 
>> +
>> +	ret = reset_control_bulk_assert(data->num_power_resets,
>> +					host->power_resets);
>> +	if (ret)
>> +		goto rpm_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);
>> +rpm_restore:
>> +	pm_runtime_resume_and_get(dev);
>> +	return ret;
>> +}
>> +
> 
> [...]
> 
>> +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 = rzg3s_pcie_probe,
>> +};
>> +module_platform_driver(rzg3s_pcie_driver);
> 
> Use builtin_platform_driver() as this driver is not supposed to be removed due
> to concersn with irqchip.

Ok

Thank you,
Claudiu

> 
> - Mani
> 



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

* Re: [PATCH v3 5/9] PCI: rzg3s-host: Add Initial PCIe Host Driver for Renesas RZ/G3S SoC
  2025-08-30 11:22     ` Claudiu Beznea
@ 2025-08-31  4:07       ` Manivannan Sadhasivam
  2025-09-01  9:25         ` Geert Uytterhoeven
  0 siblings, 1 reply; 47+ messages in thread
From: Manivannan Sadhasivam @ 2025-08-31  4:07 UTC (permalink / raw)
  To: Claudiu Beznea
  Cc: bhelgaas, lpieralisi, kwilczynski, robh, krzk+dt, conor+dt,
	geert+renesas, magnus.damm, catalin.marinas, will, mturquette,
	sboyd, p.zabel, lizhi.hou, linux-pci, linux-renesas-soc,
	devicetree, linux-kernel, linux-arm-kernel, linux-clk,
	Claudiu Beznea, Wolfram Sang

On Sat, Aug 30, 2025 at 02:22:45PM GMT, Claudiu Beznea wrote:
> 
> 
> On 30.08.2025 09:59, Manivannan Sadhasivam wrote:
> > On Fri, Jul 04, 2025 at 07:14:05PM GMT, Claudiu wrote:
> >> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> >>
> >> 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
> >>
> >> Link: https://www.renesas.com/en/products/rz-g3s?queryID=695cc067c2d89e3f271d43656ede4d12
> >> Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
> >> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> >> ---
> >>
> > 
> > [...]
> > 
> >> +static bool 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);
> >> +
> >> +	return !!ret || (val & RZG3S_PCI_REQISS_MOR_STATUS);
> > 
> > You don't need to do !!ret as the C11 standard guarantees that any scalar type
> > stored as bool will have the value of 0 or 1.
> 
> OK, will drop it anyway as suggested in another thread.
> 
> > 
> >> +}
> >> +
> > 
> > [...]
> > 
> >> +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;
> > 
> > Is it really possible to have devfn as non-zero for a root bus?
> 
> I will drop it.
> 
> > 
> >> +
> >> +	return host->pcie + where;
> >> +}
> >> +
> > 
> > [...]
> > 
> >> +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 need to be within any AXI window. Find
> >> +	 * an AXI window to setup the MSI window.
> > 
> > Are you really finding the AXI window or just making sure that the MSI window
> > falls into one of the AXI window?
> 
> I'm making sure the MSI windows falls into one of the enabled AXI windows.
> 

Then you need to reword the comment as such. Currently, it is not clear.

> > 
> > And I believe it is OK to have more than one MSI window within an AXI window.
> 
> This IP supports a single MSI window that need to fit into one of the
> enabled AXI windows.
> 

[...]

> >> +
> >> +	/* Update vendor ID and device ID */
> > 
> > Are you really updating it or setting it? If you are updating it, are the
> > default IDs invalid?
> 
> Default IDs are valid (at least on RZ/G3S) but Renesas specific. Renesas
> wants to let individual users to set their own IDs.
> 

So they are optional then? But the binding treats them as required, which should
be changed if the default IDs are valid.

> > 
> >> +	writew(host->vendor_id, host->pcie + PCI_VENDOR_ID);
> >> +	writew(host->device_id, host->pcie + PCI_DEVICE_ID);
> >> +
> >> +	/* HW manual recommends to write 0xffffffff on initialization */
> >> +	writel(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00L);
> >> +	writel(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00U);
> >> +
> >> +	/* Update bus info. */
> >> +	writeb(primary_bus, host->pcie + PCI_PRIMARY_BUS);
> >> +	writeb(secondary_bus, host->pcie + PCI_SECONDARY_BUS);
> >> +	writeb(subordinate_bus, host->pcie + PCI_SUBORDINATE_BUS);
> >> +
> >> +	/* Disable access control to the CFGU */
> >> +	writel(0, host->axi + RZG3S_PCI_PERM);
> >> +
> >> +	return 0;
> >> +}
> >> +
> > 
> > [...]
> > 
> >> +static int rzg3s_pcie_host_init(struct rzg3s_pcie_host *host, bool probe)
> >> +{
> >> +	u32 val;
> >> +	int ret;
> >> +
> >> +	/* Initialize the PCIe related registers */
> >> +	ret = rzg3s_pcie_config_init(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)
> >> +		return ret;
> >> +
> >> +	/* 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,
> >> +				 PCIE_LINK_WAIT_SLEEP_MS *
> >> +				 PCIE_LINK_WAIT_MAX_RETRIES * MILLI);
> >> +	if (ret) {
> >> +		reset_control_bulk_assert(host->data->num_cfg_resets,
> >> +					  host->cfg_resets);
> >> +		return ret;
> >> +	}
> >> +
> >> +	val = readl(host->axi + RZG3S_PCI_PCSTAT2);
> >> +	dev_info(host->dev, "PCIe link status [0x%x]\n", val);
> >> +
> >> +	val = FIELD_GET(RZG3S_PCI_PCSTAT2_STATE_RX_DETECT, val);
> >> +	dev_info(host->dev, "PCIe x%d: link up\n", hweight32(val));
> >> +
> >> +	if (probe) {
> >> +		ret = devm_add_action_or_reset(host->dev,
> >> +					       rzg3s_pcie_cfg_resets_action,
> >> +					       host);
> > 
> > Oh well, this gets ugly. Now the devm_add_action_or_reset() is sprinkled
> > throughout the driver :/
> > 
> > As I said earlier, there are concerns in unloading the driver if it implements
> > an irqchip. So if you change the module_platform_driver() to
> > builtin_platform_driver() for this driver, these devm_add_action_or_reset()
> > calls become unused.
> 
> They can still be useful in case the probe fails. As the initialization
> path is complicated, having actions or resets looks to me that makes the
> code cleaner as the rest of devm_* helpers.
> 
> I can drop it and replace with gotos and dedicated functions but this will
> complicate the code, AFAICT.
> 
> Please let me know how would you like me to proceed.
> 

It is generally preferred to cleanup the resources in err path using goto
labels.

> > 
> >> +	}
> >> +
> >> +	return ret;
> >> +}
> >> +

[...]

> >> +	ret = pm_runtime_resume_and_get(dev);
> >> +	if (ret)
> >> +		return ret;
> >> +
> > 
> > Do you really need to do resume_and_get()? If not, you should do:
> 
> It it's needed to enable the clock PM domain the device is part of.
> 

I've replied below.

> > 
> > 	pm_runtime_set_active()
> > 	pm_runtime_no_callbacks()
> > 	devm_pm_runtime_enable()
> > 
> >> +	ret = devm_add_action_or_reset(dev, rzg3s_pcie_pm_runtime_put, dev);
> >> +	if (ret)
> >> +		return ret;
> >> +
> >> +	raw_spin_lock_init(&host->hw_lock);
> >> +
> >> +	ret = rzg3s_pcie_host_setup(host, rzg3s_pcie_intx_setup,
> >> +				    rzg3s_pcie_msi_enable, true);
> >> +	if (ret)
> >> +		return ret;
> >> +
> >> +	msleep(PCIE_RESET_CONFIG_WAIT_MS);
> >> +
> >> +	bridge->sysdata = host;
> >> +	bridge->ops = &rzg3s_pcie_root_ops;
> >> +	bridge->child_ops = &rzg3s_pcie_child_ops;
> >> +	ret = pci_host_probe(bridge);
> >> +	if (ret)
> >> +		return ret;
> >> +
> >> +	return devm_add_action_or_reset(dev, rzg3s_pcie_host_remove_action,
> >> +					host);
> >> +}
> >> +
> >> +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 regmap *sysc = host->sysc;
> >> +	int ret;
> >> +
> >> +	ret = pm_runtime_put_sync(dev);
> >> +	if (ret)
> >> +		return ret;
> > 
> > Since there are no runtime callbacks present, managing runtime PM in the driver
> > makes no sense.
> 
> The PCIe device is part of a clock power domain. Dropping
> pm_runtime_enable()/pm_runtime_put_sync() in this driver will lead to this
> IP failing to work as its clocks will not be enabled/disabled. If you don't
> like the pm_runtime_* approach that could be replaced with:
> 
> devm_clk_get_enabled() in probe and clk_disable()/clk_enable() on
> suspend/resume. W/o clocks the IP can't work.
> 

Yes, you should explicitly handle clocks in the driver. Runtime PM makes sense
if you have a power domain attached to the IP, which you also do as I see now.
So to conclude, you should enable/disable the clocks explicitly for managing
clocks and use runtime PM APIs for managing the power domain associated with
clock controller.

But please add a comment above pm_runtime_resume_and_get() to make it clear as
most of the controller drivers are calling it for no reason.

- Mani

-- 
மணிவண்ணன் சதாசிவம்


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

* Re: [PATCH v3 5/9] PCI: rzg3s-host: Add Initial PCIe Host Driver for Renesas RZ/G3S SoC
  2025-08-31  4:07       ` Manivannan Sadhasivam
@ 2025-09-01  9:25         ` Geert Uytterhoeven
  2025-09-01 14:03           ` Manivannan Sadhasivam
  0 siblings, 1 reply; 47+ messages in thread
From: Geert Uytterhoeven @ 2025-09-01  9:25 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Claudiu Beznea, bhelgaas, lpieralisi, kwilczynski, robh, krzk+dt,
	conor+dt, geert+renesas, magnus.damm, catalin.marinas, will,
	mturquette, sboyd, p.zabel, lizhi.hou, linux-pci,
	linux-renesas-soc, devicetree, linux-kernel, linux-arm-kernel,
	linux-clk, Claudiu Beznea, Wolfram Sang

Hi Mani,

On Sun, 31 Aug 2025 at 06:07, Manivannan Sadhasivam <mani@kernel.org> wrote:
> On Sat, Aug 30, 2025 at 02:22:45PM GMT, Claudiu Beznea wrote:
> > On 30.08.2025 09:59, Manivannan Sadhasivam wrote:
> > > On Fri, Jul 04, 2025 at 07:14:05PM GMT, Claudiu wrote:
> > >> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> > >>
> > >> 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
> > >>
> > >> Link: https://www.renesas.com/en/products/rz-g3s?queryID=695cc067c2d89e3f271d43656ede4d12
> > >> Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
> > >> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

> > >> +  ret = pm_runtime_resume_and_get(dev);
> > >> +  if (ret)
> > >> +          return ret;
> > >> +
> > >
> > > Do you really need to do resume_and_get()? If not, you should do:
> >
> > It it's needed to enable the clock PM domain the device is part of.
> >
>
> I've replied below.
>
> > >
> > >     pm_runtime_set_active()
> > >     pm_runtime_no_callbacks()
> > >     devm_pm_runtime_enable()

> > >> +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 regmap *sysc = host->sysc;
> > >> +  int ret;
> > >> +
> > >> +  ret = pm_runtime_put_sync(dev);
> > >> +  if (ret)
> > >> +          return ret;
> > >
> > > Since there are no runtime callbacks present, managing runtime PM in the driver
> > > makes no sense.
> >
> > The PCIe device is part of a clock power domain. Dropping
> > pm_runtime_enable()/pm_runtime_put_sync() in this driver will lead to this
> > IP failing to work as its clocks will not be enabled/disabled. If you don't
> > like the pm_runtime_* approach that could be replaced with:
> >
> > devm_clk_get_enabled() in probe and clk_disable()/clk_enable() on
> > suspend/resume. W/o clocks the IP can't work.
>
> Yes, you should explicitly handle clocks in the driver. Runtime PM makes sense
> if you have a power domain attached to the IP, which you also do as I see now.
> So to conclude, you should enable/disable the clocks explicitly for managing
> clocks and use runtime PM APIs for managing the power domain associated with
> clock controller.

Why? For the past decade, we've been trying to get rid of explicit
module clock handling for all devices that are always part of a
clock domain.

The Linux PM Domain abstraction is meant for both power and clock
domains.  This is especially useful when a device is present on multiple
SoCs, on some also part of a power domain,  and the number of module
clocks that needs to be enabled for it to function is not the same on
all SoCs.  In such cases, the PM Domain abstraction takes care of many
of the integration-specific differences.

> But please add a comment above pm_runtime_resume_and_get() to make it clear as
> most of the controller drivers are calling it for no reason.

Note that any child device that uses Runtime PM depends on all
its parents in the hierarchy to call pm_runtime_enable() and
pm_runtime_resume_and_get().

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds


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

* Re: [PATCH v3 5/9] PCI: rzg3s-host: Add Initial PCIe Host Driver for Renesas RZ/G3S SoC
  2025-09-01  9:25         ` Geert Uytterhoeven
@ 2025-09-01 14:03           ` Manivannan Sadhasivam
  2025-09-01 14:22             ` Geert Uytterhoeven
  0 siblings, 1 reply; 47+ messages in thread
From: Manivannan Sadhasivam @ 2025-09-01 14:03 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Claudiu Beznea, bhelgaas, lpieralisi, kwilczynski, robh, krzk+dt,
	conor+dt, geert+renesas, magnus.damm, catalin.marinas, will,
	mturquette, sboyd, p.zabel, lizhi.hou, linux-pci,
	linux-renesas-soc, devicetree, linux-kernel, linux-arm-kernel,
	linux-clk, Claudiu Beznea, Wolfram Sang

On Mon, Sep 01, 2025 at 11:25:30AM GMT, Geert Uytterhoeven wrote:
> Hi Mani,
> 
> On Sun, 31 Aug 2025 at 06:07, Manivannan Sadhasivam <mani@kernel.org> wrote:
> > On Sat, Aug 30, 2025 at 02:22:45PM GMT, Claudiu Beznea wrote:
> > > On 30.08.2025 09:59, Manivannan Sadhasivam wrote:
> > > > On Fri, Jul 04, 2025 at 07:14:05PM GMT, Claudiu wrote:
> > > >> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> > > >>
> > > >> 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
> > > >>
> > > >> Link: https://www.renesas.com/en/products/rz-g3s?queryID=695cc067c2d89e3f271d43656ede4d12
> > > >> Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
> > > >> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> 
> > > >> +  ret = pm_runtime_resume_and_get(dev);
> > > >> +  if (ret)
> > > >> +          return ret;
> > > >> +
> > > >
> > > > Do you really need to do resume_and_get()? If not, you should do:
> > >
> > > It it's needed to enable the clock PM domain the device is part of.
> > >
> >
> > I've replied below.
> >
> > > >
> > > >     pm_runtime_set_active()
> > > >     pm_runtime_no_callbacks()
> > > >     devm_pm_runtime_enable()
> 
> > > >> +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 regmap *sysc = host->sysc;
> > > >> +  int ret;
> > > >> +
> > > >> +  ret = pm_runtime_put_sync(dev);
> > > >> +  if (ret)
> > > >> +          return ret;
> > > >
> > > > Since there are no runtime callbacks present, managing runtime PM in the driver
> > > > makes no sense.
> > >
> > > The PCIe device is part of a clock power domain. Dropping
> > > pm_runtime_enable()/pm_runtime_put_sync() in this driver will lead to this
> > > IP failing to work as its clocks will not be enabled/disabled. If you don't
> > > like the pm_runtime_* approach that could be replaced with:
> > >
> > > devm_clk_get_enabled() in probe and clk_disable()/clk_enable() on
> > > suspend/resume. W/o clocks the IP can't work.
> >
> > Yes, you should explicitly handle clocks in the driver. Runtime PM makes sense
> > if you have a power domain attached to the IP, which you also do as I see now.
> > So to conclude, you should enable/disable the clocks explicitly for managing
> > clocks and use runtime PM APIs for managing the power domain associated with
> > clock controller.
> 
> Why? For the past decade, we've been trying to get rid of explicit
> module clock handling for all devices that are always part of a
> clock domain.
> 
> The Linux PM Domain abstraction is meant for both power and clock
> domains.  This is especially useful when a device is present on multiple
> SoCs, on some also part of a power domain,  and the number of module
> clocks that needs to be enabled for it to function is not the same on
> all SoCs.  In such cases, the PM Domain abstraction takes care of many
> of the integration-specific differences.
> 

Hmm, my understanding was that we need to explicitly handle clocks from the
consumer drivers. But that maybe because, the client drivers I've dealt with
requires configuring the clocks (like setting the rate, re-parenting etc...) on
their own. But if there is no such requirement, then I guess it is OK to rely on
the PM core and clock controller drivers.

Thanks for clarifying.

> > But please add a comment above pm_runtime_resume_and_get() to make it clear as
> > most of the controller drivers are calling it for no reason.
> 
> Note that any child device that uses Runtime PM depends on all
> its parents in the hierarchy to call pm_runtime_enable() and
> pm_runtime_resume_and_get().
> 

Two things to note from your statement:

1. 'child device that uses runtime PM' - Not all child drivers are doing
runtime PM on their own. So there is no need to do pm_runtime_resume_and_get()
unless they depend on the parent for resource enablement as below.

2. 'child devices depending on parents in the hierarchy' - Again, not all
child drivers require their parent to enable the resources. In those cases, they
can just call pm_runtime_set_active() and pm_runtime_enable() in their probe.
There is absolutely no need to do pm_runtime_resume_and_get() AFAIK (correct me
if I'm wrong).

- Mani

-- 
மணிவண்ணன் சதாசிவம்


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

* Re: [PATCH v3 5/9] PCI: rzg3s-host: Add Initial PCIe Host Driver for Renesas RZ/G3S SoC
  2025-09-01 14:03           ` Manivannan Sadhasivam
@ 2025-09-01 14:22             ` Geert Uytterhoeven
  2025-09-01 15:54               ` Manivannan Sadhasivam
  0 siblings, 1 reply; 47+ messages in thread
From: Geert Uytterhoeven @ 2025-09-01 14:22 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Claudiu Beznea, bhelgaas, lpieralisi, kwilczynski, robh, krzk+dt,
	conor+dt, magnus.damm, catalin.marinas, will, mturquette, sboyd,
	p.zabel, lizhi.hou, linux-pci, linux-renesas-soc, devicetree,
	linux-kernel, linux-arm-kernel, linux-clk, Claudiu Beznea,
	Wolfram Sang

Hi Mani,

On Mon, 1 Sept 2025 at 16:04, Manivannan Sadhasivam <mani@kernel.org> wrote:
> On Mon, Sep 01, 2025 at 11:25:30AM GMT, Geert Uytterhoeven wrote:
> > On Sun, 31 Aug 2025 at 06:07, Manivannan Sadhasivam <mani@kernel.org> wrote:
> > > On Sat, Aug 30, 2025 at 02:22:45PM GMT, Claudiu Beznea wrote:
> > > > On 30.08.2025 09:59, Manivannan Sadhasivam wrote:
> > > > > On Fri, Jul 04, 2025 at 07:14:05PM GMT, Claudiu wrote:
> > > > >> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> > > > >>
> > > > >> 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
> > > > >>
> > > > >> Link: https://www.renesas.com/en/products/rz-g3s?queryID=695cc067c2d89e3f271d43656ede4d12
> > > > >> Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
> > > > >> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> >
> > > > >> +  ret = pm_runtime_resume_and_get(dev);
> > > > >> +  if (ret)
> > > > >> +          return ret;
> > > > >> +
> > > > >
> > > > > Do you really need to do resume_and_get()? If not, you should do:
> > > >
> > > > It it's needed to enable the clock PM domain the device is part of.
> > > >
> > >
> > > I've replied below.
> > >
> > > > >
> > > > >     pm_runtime_set_active()
> > > > >     pm_runtime_no_callbacks()
> > > > >     devm_pm_runtime_enable()
> >
> > > > >> +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 regmap *sysc = host->sysc;
> > > > >> +  int ret;
> > > > >> +
> > > > >> +  ret = pm_runtime_put_sync(dev);
> > > > >> +  if (ret)
> > > > >> +          return ret;
> > > > >
> > > > > Since there are no runtime callbacks present, managing runtime PM in the driver
> > > > > makes no sense.
> > > >
> > > > The PCIe device is part of a clock power domain. Dropping
> > > > pm_runtime_enable()/pm_runtime_put_sync() in this driver will lead to this
> > > > IP failing to work as its clocks will not be enabled/disabled. If you don't
> > > > like the pm_runtime_* approach that could be replaced with:
> > > >
> > > > devm_clk_get_enabled() in probe and clk_disable()/clk_enable() on
> > > > suspend/resume. W/o clocks the IP can't work.
> > >
> > > Yes, you should explicitly handle clocks in the driver. Runtime PM makes sense
> > > if you have a power domain attached to the IP, which you also do as I see now.
> > > So to conclude, you should enable/disable the clocks explicitly for managing
> > > clocks and use runtime PM APIs for managing the power domain associated with
> > > clock controller.
> >
> > Why? For the past decade, we've been trying to get rid of explicit
> > module clock handling for all devices that are always part of a
> > clock domain.
> >
> > The Linux PM Domain abstraction is meant for both power and clock
> > domains.  This is especially useful when a device is present on multiple
> > SoCs, on some also part of a power domain,  and the number of module
> > clocks that needs to be enabled for it to function is not the same on
> > all SoCs.  In such cases, the PM Domain abstraction takes care of many
> > of the integration-specific differences.
>
> Hmm, my understanding was that we need to explicitly handle clocks from the
> consumer drivers. But that maybe because, the client drivers I've dealt with
> requires configuring the clocks (like setting the rate, re-parenting etc...) on
> their own. But if there is no such requirement, then I guess it is OK to rely on
> the PM core and clock controller drivers.

When you need to know the actual clock rate, or change it, you
indeed have to handle the clock explicitly.  But it still may be enabled
automatically through the clock domain.

> > > But please add a comment above pm_runtime_resume_and_get() to make it clear as
> > > most of the controller drivers are calling it for no reason.
> >
> > Note that any child device that uses Runtime PM depends on all
> > its parents in the hierarchy to call pm_runtime_enable() and
> > pm_runtime_resume_and_get().
>
> Two things to note from your statement:
>
> 1. 'child device that uses runtime PM' - Not all child drivers are doing
> runtime PM on their own. So there is no need to do pm_runtime_resume_and_get()
> unless they depend on the parent for resource enablement as below.

It indeed depends on the child device, and on the bus.  For e.g. an
Ethernet controller connected to a simple SoC expansion bus, the bus must
be powered and clock, which is what "simple-pm-bus" takes care of
("simple-bus" does not).

> 2. 'child devices depending on parents in the hierarchy' - Again, not all
> child drivers require their parent to enable the resources. In those cases, they
> can just call pm_runtime_set_active() and pm_runtime_enable() in their probe.
> There is absolutely no need to do pm_runtime_resume_and_get() AFAIK (correct me
> if I'm wrong).

pm_runtime_set_active() may be sufficient, but I am not 100% sure.

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds


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

* Re: [PATCH v3 5/9] PCI: rzg3s-host: Add Initial PCIe Host Driver for Renesas RZ/G3S SoC
  2025-09-01 14:22             ` Geert Uytterhoeven
@ 2025-09-01 15:54               ` Manivannan Sadhasivam
  0 siblings, 0 replies; 47+ messages in thread
From: Manivannan Sadhasivam @ 2025-09-01 15:54 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Claudiu Beznea, bhelgaas, lpieralisi, kwilczynski, robh, krzk+dt,
	conor+dt, magnus.damm, catalin.marinas, will, mturquette, sboyd,
	p.zabel, lizhi.hou, linux-pci, linux-renesas-soc, devicetree,
	linux-kernel, linux-arm-kernel, linux-clk, Claudiu Beznea,
	Wolfram Sang

On Mon, Sep 01, 2025 at 04:22:16PM GMT, Geert Uytterhoeven wrote:
> Hi Mani,
> 
> On Mon, 1 Sept 2025 at 16:04, Manivannan Sadhasivam <mani@kernel.org> wrote:
> > On Mon, Sep 01, 2025 at 11:25:30AM GMT, Geert Uytterhoeven wrote:
> > > On Sun, 31 Aug 2025 at 06:07, Manivannan Sadhasivam <mani@kernel.org> wrote:
> > > > On Sat, Aug 30, 2025 at 02:22:45PM GMT, Claudiu Beznea wrote:
> > > > > On 30.08.2025 09:59, Manivannan Sadhasivam wrote:
> > > > > > On Fri, Jul 04, 2025 at 07:14:05PM GMT, Claudiu wrote:
> > > > > >> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> > > > > >>
> > > > > >> 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
> > > > > >>
> > > > > >> Link: https://www.renesas.com/en/products/rz-g3s?queryID=695cc067c2d89e3f271d43656ede4d12
> > > > > >> Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
> > > > > >> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> > >
> > > > > >> +  ret = pm_runtime_resume_and_get(dev);
> > > > > >> +  if (ret)
> > > > > >> +          return ret;
> > > > > >> +
> > > > > >
> > > > > > Do you really need to do resume_and_get()? If not, you should do:
> > > > >
> > > > > It it's needed to enable the clock PM domain the device is part of.
> > > > >
> > > >
> > > > I've replied below.
> > > >
> > > > > >
> > > > > >     pm_runtime_set_active()
> > > > > >     pm_runtime_no_callbacks()
> > > > > >     devm_pm_runtime_enable()
> > >
> > > > > >> +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 regmap *sysc = host->sysc;
> > > > > >> +  int ret;
> > > > > >> +
> > > > > >> +  ret = pm_runtime_put_sync(dev);
> > > > > >> +  if (ret)
> > > > > >> +          return ret;
> > > > > >
> > > > > > Since there are no runtime callbacks present, managing runtime PM in the driver
> > > > > > makes no sense.
> > > > >
> > > > > The PCIe device is part of a clock power domain. Dropping
> > > > > pm_runtime_enable()/pm_runtime_put_sync() in this driver will lead to this
> > > > > IP failing to work as its clocks will not be enabled/disabled. If you don't
> > > > > like the pm_runtime_* approach that could be replaced with:
> > > > >
> > > > > devm_clk_get_enabled() in probe and clk_disable()/clk_enable() on
> > > > > suspend/resume. W/o clocks the IP can't work.
> > > >
> > > > Yes, you should explicitly handle clocks in the driver. Runtime PM makes sense
> > > > if you have a power domain attached to the IP, which you also do as I see now.
> > > > So to conclude, you should enable/disable the clocks explicitly for managing
> > > > clocks and use runtime PM APIs for managing the power domain associated with
> > > > clock controller.
> > >
> > > Why? For the past decade, we've been trying to get rid of explicit
> > > module clock handling for all devices that are always part of a
> > > clock domain.
> > >
> > > The Linux PM Domain abstraction is meant for both power and clock
> > > domains.  This is especially useful when a device is present on multiple
> > > SoCs, on some also part of a power domain,  and the number of module
> > > clocks that needs to be enabled for it to function is not the same on
> > > all SoCs.  In such cases, the PM Domain abstraction takes care of many
> > > of the integration-specific differences.
> >
> > Hmm, my understanding was that we need to explicitly handle clocks from the
> > consumer drivers. But that maybe because, the client drivers I've dealt with
> > requires configuring the clocks (like setting the rate, re-parenting etc...) on
> > their own. But if there is no such requirement, then I guess it is OK to rely on
> > the PM core and clock controller drivers.
> 
> When you need to know the actual clock rate, or change it, you
> indeed have to handle the clock explicitly.  But it still may be enabled
> automatically through the clock domain.
> 

Yeah!

> > > > But please add a comment above pm_runtime_resume_and_get() to make it clear as
> > > > most of the controller drivers are calling it for no reason.
> > >
> > > Note that any child device that uses Runtime PM depends on all
> > > its parents in the hierarchy to call pm_runtime_enable() and
> > > pm_runtime_resume_and_get().
> >
> > Two things to note from your statement:
> >
> > 1. 'child device that uses runtime PM' - Not all child drivers are doing
> > runtime PM on their own. So there is no need to do pm_runtime_resume_and_get()
> > unless they depend on the parent for resource enablement as below.
> 
> It indeed depends on the child device, and on the bus.  For e.g. an
> Ethernet controller connected to a simple SoC expansion bus, the bus must
> be powered and clock, which is what "simple-pm-bus" takes care of
> ("simple-bus" does not).
> 

Right. But most of the PCI controller drivers call pm_runtime_resume_and_get()
for no good reasons. They might have just copied the code from a driver that did
it on purpose. So I tend to scrutinize these calls whenever they get added for a
driver.

- Mani

-- 
மணிவண்ணன் சதாசிவம்


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

end of thread, other threads:[~2025-09-01 23:12 UTC | newest]

Thread overview: 47+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-04 16:14 [PATCH v3 0/9] PCI: rzg3s-host: Add PCIe driver for Renesas RZ/G3S SoC Claudiu
2025-07-04 16:14 ` [PATCH v3 1/9] soc: renesas: rz-sysc: Add syscon/regmap support Claudiu
2025-07-04 16:14 ` [PATCH v3 2/9] clk: renesas: r9a08g045: Add clocks and resets support for PCIe Claudiu
2025-08-04 10:25   ` Geert Uytterhoeven
2025-07-04 16:14 ` [PATCH v3 3/9] PCI: of_property: Restore the arguments of the next level parent Claudiu
2025-08-20 17:47   ` Manivannan Sadhasivam
2025-08-21  7:40     ` Claudiu Beznea
2025-08-30  4:10       ` Manivannan Sadhasivam
2025-07-04 16:14 ` [PATCH v3 4/9] dt-bindings: PCI: renesas,r9a08g045s33-pcie: Add documentation for the PCIe IP on Renesas RZ/G3S Claudiu
2025-07-08 16:34   ` Bjorn Helgaas
2025-07-09  6:47     ` Krzysztof Kozlowski
2025-07-09 13:24       ` Bjorn Helgaas
2025-07-09 13:43         ` Krzysztof Kozlowski
2025-08-08 11:26           ` Claudiu Beznea
2025-08-08 12:03             ` Geert Uytterhoeven
2025-08-08 11:25     ` Claudiu Beznea
2025-08-08 16:23       ` Bjorn Helgaas
2025-08-28 19:11       ` claudiu beznea
2025-08-28 19:36         ` Bjorn Helgaas
2025-08-29  5:03           ` claudiu beznea
2025-07-04 16:14 ` [PATCH v3 5/9] PCI: rzg3s-host: Add Initial PCIe Host Driver for Renesas RZ/G3S SoC Claudiu
2025-07-08 19:24   ` Bjorn Helgaas
2025-08-08 11:24     ` Claudiu Beznea
2025-08-30  6:59   ` Manivannan Sadhasivam
2025-08-30 11:22     ` Claudiu Beznea
2025-08-31  4:07       ` Manivannan Sadhasivam
2025-09-01  9:25         ` Geert Uytterhoeven
2025-09-01 14:03           ` Manivannan Sadhasivam
2025-09-01 14:22             ` Geert Uytterhoeven
2025-09-01 15:54               ` Manivannan Sadhasivam
2025-07-04 16:14 ` [PATCH v3 6/9] arm64: dts: renesas: r9a08g045s33: Add PCIe node Claudiu
2025-08-08 12:13   ` Geert Uytterhoeven
2025-07-04 16:14 ` [PATCH v3 7/9] arm64: dts: renesas: rzg3s-smarc-som: Update dma-ranges for PCIe Claudiu
2025-07-07  8:18   ` Biju Das
2025-07-08 10:09     ` Claudiu Beznea
2025-07-09  5:05       ` Biju Das
2025-08-08 11:28         ` Claudiu Beznea
2025-08-08 11:44           ` Biju Das
2025-08-08 12:03             ` Claudiu Beznea
2025-08-08 11:45         ` Geert Uytterhoeven
2025-07-08 16:55   ` Bjorn Helgaas
2025-08-08 11:24     ` Claudiu Beznea
2025-07-04 16:14 ` [PATCH v3 8/9] arm64: dts: renesas: rzg3s-smarc: Enable PCIe Claudiu
2025-07-04 16:14 ` [PATCH v3 9/9] arm64: defconfig: Enable PCIe for the Renesas RZ/G3S SoC Claudiu
2025-07-07  6:41 ` [PATCH v3 0/9] PCI: rzg3s-host: Add PCIe driver for " Wolfram Sang
2025-07-07  8:05   ` Claudiu Beznea
2025-07-07 12:01     ` Wolfram Sang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).