[PATCH v3 5/6] PCI: dwc: rcar-gen4: Handle PERST via reset subsystem
Marek Vasut <[email protected]> Tue, 28 Jul 2026 03:32:38 +0200
| Newsgroups | org.kernel.vger.linux-renesas-soc,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci |
|---|---|
| Message-ID | <[email protected]> |
Handle PERST via both GPIO and reset subsystem. On R-Car Gen4, the PERST signal is operated as a GPIO, on R-Car Gen5 it might only be accessible via SCMI reset via reset subsystem. Support both options. This is a preparatory patch for R-Car Gen5 support. Signed-off-by: Marek Vasut <[email protected]> --- Cc: "Krzysztof WilczyĆski" <[email protected]> Cc: Bjorn Helgaas <[email protected]> Cc: Conor Dooley <[email protected]> Cc: Geert Uytterhoeven <[email protected]> Cc: Krzysztof Kozlowski <[email protected]> Cc: Lorenzo Pieralisi <[email protected]> Cc: Manivannan Sadhasivam <[email protected]> Cc: Rob Herring <[email protected]> Cc: Yoshihiro Shimoda <[email protected]> Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] --- V2: - Use dev_err_probe() for perst in rcar_gen4_pcie_get_resources() - Use of_get_next_available_child() to obtain root port OF node - Switch to of_reset_control_get_optional_exclusive() to deal with R-Car Gen4, where the PERST is handled as GPIO instead of reset - Rename rcar_gen4_pcie_host_perst() to rcar_gen4_pcie_host_perst_assert() and use bool type for assert and deassert selection - Add missing reset_control_put() into rcar_gen4_pcie_probe() fail path V3: - Handle controllers without root port DT node - Swap fail path order --- drivers/pci/controller/dwc/pcie-rcar-gen4.c | 44 +++++++++++++++++++-- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c index ff1969338a276..30b024a620410 100644 --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c @@ -99,6 +99,7 @@ struct rcar_gen4_pcie { void __iomem *base; void __iomem *phy_base; struct platform_device *pdev; + struct reset_control *perst; const struct rcar_gen4_pcie_drvdata *drvdata; }; #define to_rcar_gen4_pcie(_dw) container_of(_dw, struct rcar_gen4_pcie, dw) @@ -317,12 +318,27 @@ static void rcar_gen4_pcie_unprepare(struct rcar_gen4_pcie *rcar) static int rcar_gen4_pcie_get_resources(struct rcar_gen4_pcie *rcar) { + struct device *dev = rcar->dw.dev; + struct device_node *root_port; + rcar->phy_base = devm_platform_ioremap_resource_byname(rcar->pdev, "phy"); if (IS_ERR(rcar->phy_base)) return PTR_ERR(rcar->phy_base); + root_port = of_get_next_available_child(dev->of_node, NULL); + if (root_port) { + rcar->perst = of_reset_control_get_optional_exclusive(root_port, "perst"); + of_node_put(root_port); + if (IS_ERR(rcar->perst)) + return dev_err_probe(dev, PTR_ERR(rcar->perst), "Failed to get PERST#\n"); + } else { + rcar->perst = NULL; + } + /* Renesas-specific registers */ rcar->base = devm_platform_ioremap_resource_byname(rcar->pdev, "app"); + if (IS_ERR(rcar->base)) + reset_control_put(rcar->perst); return PTR_ERR_OR_ZERO(rcar->base); } @@ -443,6 +459,22 @@ static int rcar_gen4_pcie_host_msi_init(struct dw_pcie_rp *pp) return ret; } +static void rcar_gen4_pcie_host_perst_assert(struct dw_pcie_rp *pp, bool assert) +{ + struct dw_pcie *dw = to_dw_pcie_from_pp(pp); + struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw); + + gpiod_set_value_cansleep(dw->pe_rst, assert); + + if (!rcar->perst) + return; + + if (assert) + reset_control_assert(rcar->perst); + else + reset_control_deassert(rcar->perst); +} + /* Host mode */ static int rcar_gen4_pcie_host_init(struct dw_pcie_rp *pp) { @@ -450,7 +482,7 @@ static int rcar_gen4_pcie_host_init(struct dw_pcie_rp *pp) struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw); int ret; - gpiod_set_value_cansleep(dw->pe_rst, 1); + rcar_gen4_pcie_host_perst_assert(pp, true); ret = rcar->drvdata->init(rcar); if (ret) @@ -471,7 +503,7 @@ static int rcar_gen4_pcie_host_init(struct dw_pcie_rp *pp) msleep(PCIE_T_PVPERL_MS); /* pe_rst requires 100msec delay */ - gpiod_set_value_cansleep(dw->pe_rst, 0); + rcar_gen4_pcie_host_perst_assert(pp, false); return 0; @@ -485,7 +517,7 @@ static void rcar_gen4_pcie_host_deinit(struct dw_pcie_rp *pp) struct dw_pcie *dw = to_dw_pcie_from_pp(pp); struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw); - gpiod_set_value_cansleep(dw->pe_rst, 1); + rcar_gen4_pcie_host_perst_assert(pp, true); rcar->drvdata->deinit(rcar); } @@ -657,7 +689,7 @@ static int rcar_gen4_pcie_probe(struct platform_device *pdev) err = rcar_gen4_pcie_prepare(rcar); if (err) - return err; + goto err_prepare; err = rcar_gen4_add_dw_pcie(rcar); if (err) @@ -668,6 +700,9 @@ static int rcar_gen4_pcie_probe(struct platform_device *pdev) err_unprepare: rcar_gen4_pcie_unprepare(rcar); +err_prepare: + reset_control_put(rcar->perst); + return err; } @@ -691,6 +726,7 @@ static void rcar_gen4_pcie_remove(struct platform_device *pdev) rcar_gen4_remove_dw_pcie(rcar); rcar_gen4_pcie_unprepare(rcar); + reset_control_put(rcar->perst); } static int r8a779f0_pcie_ltssm_control(struct rcar_gen4_pcie *rcar, bool enable) -- 2.53.0