Thread (22 messages) 22 messages, 2 authors, 2026-02-18
STALE144d
Revisions (10)
  1. v1 [diff vs current]
  2. v2 [diff vs current]
  3. v3 [diff vs current]
  4. v4 [diff vs current]
  5. v5 current
  6. v6 [diff vs current]
  7. v7 [diff vs current]
  8. v8 [diff vs current]
  9. v1 [diff vs current]
  10. v1 [diff vs current]

[PATCH v5 13/16] PCI: rzg3s-host: Add support for RZ/G3E PCIe controller

From: John Madieu <john.madieu.xa@bp.renesas.com>
Date: 2026-02-10 11:33:30
Also in: linux-clk, linux-pci, linux-renesas-soc
Subsystem: pci native host bridge and endpoint drivers, pci subsystem, pcie driver for renesas rz/g3s series, the rest · Maintainers: Lorenzo Pieralisi, Krzysztof Wilczyński, Manivannan Sadhasivam, Bjorn Helgaas, Claudiu Beznea, Linus Torvalds

Add support for the PCIe controller found in RZ/G3E SoCs to the existing
RZ/G3S PCIe host driver. The RZ/G3E PCIe controller is similar to the
RZ/G3S's, with the following key differences:

 - Supports PCIe Gen3 (8.0 GT/s) link speeds alongside Gen2 (5.0 GT/s)
 - Uses a different reset control mechanism via AXI registers instead
   of the Linux reset framework
 - Requires specific SYSC configuration for link state control and
   Root Complex mode selection

Signed-off-by: John Madieu <john.madieu.xa@bp.renesas.com>
---

Changes:

v5:
 - Introduce rzg3s_sysc_config() helper for sys configuration

v4: No changes
v3: No changes
v2: Collected tag.

 drivers/pci/controller/pcie-rzg3s-host.c | 152 ++++++++++++++++++++---
 1 file changed, 137 insertions(+), 15 deletions(-)
diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c
index 22858a876fd8..77313cc01c02 100644
--- a/drivers/pci/controller/pcie-rzg3s-host.c
+++ b/drivers/pci/controller/pcie-rzg3s-host.c
@@ -111,6 +111,16 @@
 #define RZG3S_PCI_PERM_CFG_HWINIT_EN		BIT(2)
 #define RZG3S_PCI_PERM_PIPE_PHY_REG_EN		BIT(1)
 
+/* RZ/G3E specific registers */
+#define RZG3E_PCI_RESET				0x310
+#define RZG3E_PCI_RESET_RST_OUT_B		BIT(6)
+#define RZG3E_PCI_RESET_RST_PS_B		BIT(5)
+#define RZG3E_PCI_RESET_RST_LOAD_B		BIT(4)
+#define RZG3E_PCI_RESET_RST_CFG_B		BIT(3)
+#define RZG3E_PCI_RESET_RST_RSM_B		BIT(2)
+#define RZG3E_PCI_RESET_RST_GP_B		BIT(1)
+#define RZG3E_PCI_RESET_RST_B			BIT(0)
+
 #define RZG3S_PCI_MSIRE(id)			(0x600 + (id) * 0x10)
 #define RZG3S_PCI_MSIRE_ENA			BIT(0)
 
@@ -183,9 +193,13 @@ struct rzg3s_sysc_function {
 /**
  * struct rzg3s_sysc_info - RZ/G3S System Controller function info
  * @rst_rsm_b: Reset RSM_B function descriptor
+ * @l1_allow: L1 power state management function descriptor
+ * @mode: Mode configuration function descriptor
  */
 struct rzg3s_sysc_info {
 	struct rzg3s_sysc_function rst_rsm_b;
+	struct rzg3s_sysc_function l1_allow;
+	struct rzg3s_sysc_function mode;
 };
 
 /**
@@ -1124,6 +1138,49 @@ static int rzg3s_config_deinit(struct rzg3s_pcie_host *host)
 					 host->cfg_resets);
 }
 
+/* RZ/G3E SoC-specific config implementations */
+static void rzg3e_pcie_config_pre_init(struct rzg3s_pcie_host *host)
+{
+	/*
+	 * De-assert LOAD_B and CFG_B during configuration phase.
+	 * These are part of the RZ/G3E reset register, not reset framework.
+	 * Other reset bits remain asserted until config_post_init.
+	 */
+	rzg3s_pcie_update_bits(host->axi, RZG3E_PCI_RESET,
+			       RZG3E_PCI_RESET_RST_LOAD_B | RZG3E_PCI_RESET_RST_CFG_B,
+			       RZG3E_PCI_RESET_RST_LOAD_B | RZG3E_PCI_RESET_RST_CFG_B);
+}
+
+static int rzg3e_config_deinit(struct rzg3s_pcie_host *host)
+{
+	writel_relaxed(0, host->axi + RZG3E_PCI_RESET);
+	return 0;
+}
+
+static int rzg3e_config_post_init(struct rzg3s_pcie_host *host)
+{
+	/* De-assert PS_B, GP_B, RST_B */
+	rzg3s_pcie_update_bits(host->axi, RZG3E_PCI_RESET,
+			       RZG3E_PCI_RESET_RST_PS_B | RZG3E_PCI_RESET_RST_GP_B |
+			       RZG3E_PCI_RESET_RST_B,
+			       RZG3E_PCI_RESET_RST_PS_B | RZG3E_PCI_RESET_RST_GP_B |
+			       RZG3E_PCI_RESET_RST_B);
+
+	/*
+	 * According to the RZ/G3E HW manual (Rev.1.15, Table 6.6-130
+	 * Initialization Procedure (RC)), hardware requires >= 500us delay
+	 * before final reset deassert.
+	 */
+	fsleep(500);
+
+	/* De-assert OUT_B and RSM_B to complete reset sequence */
+	rzg3s_pcie_update_bits(host->axi, RZG3E_PCI_RESET,
+			       RZG3E_PCI_RESET_RST_OUT_B | RZG3E_PCI_RESET_RST_RSM_B,
+			       RZG3E_PCI_RESET_RST_OUT_B | RZG3E_PCI_RESET_RST_RSM_B);
+
+	return 0;
+}
+
 static void rzg3s_pcie_irq_init(struct rzg3s_pcie_host *host)
 {
 	/*
@@ -1266,6 +1323,47 @@ static int rzg3s_pcie_host_init_port(struct rzg3s_pcie_host *host)
 	return ret;
 }
 
+/**
+ * rzg3s_sysc_config - Configure SYSC registers for PCIe
+ * @sysc: SYSC descriptor
+ * @mode: Mode value to set (-1 to skip)
+ * @rsm_b: RST_RSM_B value to set (-1 to skip)
+ * @l1_allow: L1_ALLOW value to set (-1 to skip)
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int rzg3s_sysc_config(struct rzg3s_sysc *sysc, int mode, int rsm_b,
+			     int l1_allow)
+{
+	const struct rzg3s_sysc_info *info = sysc->info;
+	int ret;
+
+	if (mode >= 0 && info->mode.mask) {
+		ret = regmap_write(sysc->regmap, info->mode.offset,
+				   field_prep(info->mode.mask, mode));
+		if (ret)
+			return ret;
+	}
+
+	if (rsm_b >= 0 && info->rst_rsm_b.mask) {
+		ret = regmap_update_bits(sysc->regmap, info->rst_rsm_b.offset,
+					 info->rst_rsm_b.mask,
+					 field_prep(info->rst_rsm_b.mask, rsm_b));
+		if (ret)
+			return ret;
+	}
+
+	if (l1_allow >= 0 && info->l1_allow.mask) {
+		ret = regmap_update_bits(sysc->regmap, info->l1_allow.offset,
+					 info->l1_allow.mask,
+					 field_prep(info->l1_allow.mask, l1_allow));
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
 static int rzg3s_pcie_host_init(struct rzg3s_pcie_host *host)
 {
 	u32 val;
@@ -1284,6 +1382,11 @@ static int rzg3s_pcie_host_init(struct rzg3s_pcie_host *host)
 	if (ret)
 		goto config_deinit;
 
+	/* Enable ASPM L1 transition for SoCs that use it */
+	ret = rzg3s_sysc_config(host->sysc, -1, -1, 1);
+	if (ret)
+		goto config_deinit;
+
 	/* Initialize the interrupts */
 	rzg3s_pcie_irq_init(host);
 
@@ -1631,9 +1734,12 @@ static int rzg3s_pcie_probe(struct platform_device *pdev)
 		goto port_refclk_put;
 	}
 
-	ret = regmap_update_bits(sysc->regmap, sysc->info->rst_rsm_b.offset,
-				 sysc->info->rst_rsm_b.mask,
-				 field_prep(sysc->info->rst_rsm_b.mask, 1));
+	/*
+	 * Put controller in RC (Root Complex) mode for SoCs that
+	 * support it. These can operate in either EP or RC mode.
+	 * While at it, do also de-assert RST_RSM_B.
+	 */
+	ret = rzg3s_sysc_config(sysc, 1, 1, -1);
 	if (ret)
 		goto port_refclk_put;
 
@@ -1685,9 +1791,7 @@ static int rzg3s_pcie_probe(struct platform_device *pdev)
 	 * SYSC RST_RSM_B signal need to be asserted before turning off the
 	 * power to the PHY.
 	 */
-	regmap_update_bits(sysc->regmap, sysc->info->rst_rsm_b.offset,
-			   sysc->info->rst_rsm_b.mask,
-			   field_prep(sysc->info->rst_rsm_b.mask, 0));
+	rzg3s_sysc_config(sysc, -1, 0, -1);
 port_refclk_put:
 	clk_put(host->port.refclk);
 
@@ -1718,9 +1822,7 @@ static int rzg3s_pcie_suspend_noirq(struct device *dev)
 	if (ret)
 		goto config_reinit;
 
-	ret = regmap_update_bits(sysc->regmap, sysc->info->rst_rsm_b.offset,
-				 sysc->info->rst_rsm_b.mask,
-				 field_prep(sysc->info->rst_rsm_b.mask, 0));
+	ret = rzg3s_sysc_config(sysc, -1, 0, -1);
 	if (ret)
 		goto power_resets_restore;
 
@@ -1745,9 +1847,7 @@ static int rzg3s_pcie_resume_noirq(struct device *dev)
 	struct rzg3s_sysc *sysc = host->sysc;
 	int ret;
 
-	ret = regmap_update_bits(sysc->regmap, sysc->info->rst_rsm_b.offset,
-				 sysc->info->rst_rsm_b.mask,
-				 field_prep(sysc->info->rst_rsm_b.mask, 1));
+	ret = rzg3s_sysc_config(sysc, 1, 1, -1);
 	if (ret)
 		return ret;
 
@@ -1776,9 +1876,7 @@ static int rzg3s_pcie_resume_noirq(struct device *dev)
 	reset_control_bulk_assert(data->num_power_resets,
 				  host->power_resets);
 assert_rst_rsm_b:
-	regmap_update_bits(sysc->regmap, sysc->info->rst_rsm_b.offset,
-			   sysc->info->rst_rsm_b.mask,
-			   field_prep(sysc->info->rst_rsm_b.mask, 0));
+	rzg3s_sysc_config(sysc, -1, 0, -1);
 	return ret;
 }
 
@@ -1811,11 +1909,35 @@ static const struct rzg3s_pcie_soc_data rzg3s_soc_data = {
 	},
 };
 
+static const char * const rzg3e_soc_power_resets[] = { "aresetn" };
+
+static const struct rzg3s_pcie_soc_data rzg3e_soc_data = {
+	.power_resets = rzg3e_soc_power_resets,
+	.num_power_resets = ARRAY_SIZE(rzg3e_soc_power_resets),
+	.config_pre_init = rzg3e_pcie_config_pre_init,
+	.config_post_init = rzg3e_config_post_init,
+	.config_deinit = rzg3e_config_deinit,
+	.sysc_info = {
+		.l1_allow = {
+			.offset = 0x1020,
+			.mask = BIT(0),
+		},
+		.mode = {
+			.offset = 0x1024,
+			.mask = BIT(0),
+		},
+	},
+};
+
 static const struct of_device_id rzg3s_pcie_of_match[] = {
 	{
 		.compatible = "renesas,r9a08g045-pcie",
 		.data = &rzg3s_soc_data,
 	},
+	{
+		.compatible = "renesas,r9a09g047-pcie",
+		.data = &rzg3e_soc_data,
+	},
 	{}
 };
 
-- 
2.25.1
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help