PCI: rcar-gen4: Handle PERST# via reset subsystem

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 work for R-Car Gen5 support.

Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Link: https://patch.msgid.link/20260921202823.72620-6-marek.vasut+renesas@mailbox.org
This commit is contained in:
Marek Vasut 2026-09-21 22:27:47 +02:00 committed by Bjorn Helgaas
parent bb0cf158cf
commit 487a731517

View File

@ -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,25 @@ 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");
}
/* 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);
}
@ -494,6 +508,21 @@ static int rcar_gen4_pcie_enable_device(struct pci_host_bridge *bridge,
return 0;
}
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);
if (dw->pe_rst) {
gpiod_set_value_cansleep(dw->pe_rst, assert);
} else {
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)
{
@ -504,7 +533,7 @@ static int rcar_gen4_pcie_host_init(struct dw_pcie_rp *pp)
if (pp->bridge)
pp->bridge->enable_device = rcar_gen4_pcie_enable_device;
gpiod_set_value_cansleep(dw->pe_rst, 1);
rcar_gen4_pcie_host_perst_assert(pp, true);
ret = rcar->drvdata->init(rcar);
if (ret)
@ -525,7 +554,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;
@ -539,7 +568,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);
}
@ -713,7 +742,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)
@ -724,6 +753,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;
}
@ -747,6 +779,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)